7d3826ea48
Update is_compiled() and has_feedback_vector() to return false in the case where the SFI's bytecode has been flushed, but the JSFunction hasn't yet been reset to uncompiled. Also add code to reset the JSFunction when it is recompiled lazily. BUG=v8:8394 Change-Id: I7c5f79066603ac1ae097a0a62c625b1a8e39431c Reviewed-on: https://chromium-review.googlesource.com/c/1363138 Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#58148}
2318 lines
80 KiB
C++
2318 lines
80 KiB
C++
// Copyright 2012 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/objects.h"
|
|
|
|
#include "src/assembler-inl.h"
|
|
#include "src/bootstrapper.h"
|
|
#include "src/counters.h"
|
|
#include "src/date.h"
|
|
#include "src/disasm.h"
|
|
#include "src/disassembler.h"
|
|
#include "src/elements.h"
|
|
#include "src/field-type.h"
|
|
#include "src/layout-descriptor.h"
|
|
#include "src/macro-assembler.h"
|
|
#include "src/objects-inl.h"
|
|
#include "src/objects/arguments-inl.h"
|
|
#include "src/objects/bigint.h"
|
|
#include "src/objects/data-handler-inl.h"
|
|
#include "src/objects/debug-objects-inl.h"
|
|
#include "src/objects/embedder-data-array-inl.h"
|
|
#include "src/objects/embedder-data-slot-inl.h"
|
|
#include "src/objects/hash-table-inl.h"
|
|
#include "src/objects/js-array-inl.h"
|
|
#ifdef V8_INTL_SUPPORT
|
|
#include "src/objects/js-break-iterator-inl.h"
|
|
#include "src/objects/js-collator-inl.h"
|
|
#endif // V8_INTL_SUPPORT
|
|
#include "src/objects/js-collection-inl.h"
|
|
#ifdef V8_INTL_SUPPORT
|
|
#include "src/objects/js-date-time-format-inl.h"
|
|
#endif // V8_INTL_SUPPORT
|
|
#include "src/objects/js-generator-inl.h"
|
|
#ifdef V8_INTL_SUPPORT
|
|
#include "src/objects/js-list-format-inl.h"
|
|
#include "src/objects/js-locale-inl.h"
|
|
#include "src/objects/js-number-format-inl.h"
|
|
#include "src/objects/js-plural-rules-inl.h"
|
|
#endif // V8_INTL_SUPPORT
|
|
#include "src/objects/js-regexp-inl.h"
|
|
#include "src/objects/js-regexp-string-iterator-inl.h"
|
|
#ifdef V8_INTL_SUPPORT
|
|
#include "src/objects/js-relative-time-format-inl.h"
|
|
#include "src/objects/js-segment-iterator-inl.h"
|
|
#include "src/objects/js-segmenter-inl.h"
|
|
#endif // V8_INTL_SUPPORT
|
|
#include "src/objects/js-weak-refs-inl.h"
|
|
#include "src/objects/literal-objects-inl.h"
|
|
#include "src/objects/maybe-object.h"
|
|
#include "src/objects/microtask-inl.h"
|
|
#include "src/objects/module-inl.h"
|
|
#include "src/objects/promise-inl.h"
|
|
#include "src/objects/stack-frame-info-inl.h"
|
|
#include "src/ostreams.h"
|
|
#include "src/regexp/jsregexp.h"
|
|
#include "src/transitions.h"
|
|
#include "src/wasm/wasm-objects-inl.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
// Heap Verification Overview
|
|
// --------------------------
|
|
// - Each InstanceType has a separate XXXVerify method which checks an object's
|
|
// integrity in isolation.
|
|
// - --verify-heap will iterate over all gc spaces and call ObjectVerify() on
|
|
// every encountered tagged pointer.
|
|
// - Verification should be pushed down to the specific instance type if its
|
|
// integrity is independent of an outer object.
|
|
// - In cases where the InstanceType is too genernic (e.g. FixedArray) the
|
|
// XXXVerify of the outer method has to do recursive verification.
|
|
// - If the corresponding objects have inheritence the parent's Verify method
|
|
// is called as well.
|
|
// - For any field containing pointes VerifyPointer(...) should be called.
|
|
//
|
|
// Caveats
|
|
// -------
|
|
// - Assume that any of the verify methods is incomplete!
|
|
// - Some integrity checks are only partially done due to objects being in
|
|
// partially initialized states when a gc happens, for instance when outer
|
|
// objects are allocted before inner ones.
|
|
//
|
|
|
|
#ifdef VERIFY_HEAP
|
|
|
|
void Object::ObjectVerify(Isolate* isolate) {
|
|
RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kObjectVerify);
|
|
if (IsSmi()) {
|
|
Smi::cast(this)->SmiVerify(isolate);
|
|
} else {
|
|
HeapObject::cast(this)->HeapObjectVerify(isolate);
|
|
}
|
|
CHECK(!IsConstructor() || IsCallable());
|
|
}
|
|
|
|
void Object::VerifyPointer(Isolate* isolate, Object* p) {
|
|
if (p->IsHeapObject()) {
|
|
HeapObject::VerifyHeapPointer(isolate, p);
|
|
} else {
|
|
CHECK(p->IsSmi());
|
|
}
|
|
}
|
|
|
|
void ObjectPtr::VerifyPointer(Isolate* isolate, Object* p) {
|
|
Object::VerifyPointer(isolate, p);
|
|
}
|
|
|
|
void MaybeObject::VerifyMaybeObjectPointer(Isolate* isolate, MaybeObject p) {
|
|
HeapObject* heap_object;
|
|
if (p->GetHeapObject(&heap_object)) {
|
|
HeapObject::VerifyHeapPointer(isolate, heap_object);
|
|
} else {
|
|
CHECK(p->IsSmi() || p->IsCleared());
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
void VerifyForeignPointer(Isolate* isolate, HeapObject* host, Object* foreign) {
|
|
host->VerifyPointer(isolate, foreign);
|
|
CHECK(foreign->IsUndefined(isolate) || Foreign::IsNormalized(foreign));
|
|
}
|
|
} // namespace
|
|
|
|
void Smi::SmiVerify(Isolate* isolate) {
|
|
CHECK(IsSmi());
|
|
CHECK(!IsCallable());
|
|
CHECK(!IsConstructor());
|
|
}
|
|
|
|
void HeapObject::HeapObjectVerify(Isolate* isolate) {
|
|
VerifyHeapPointer(isolate, map());
|
|
CHECK(map()->IsMap());
|
|
|
|
switch (map()->instance_type()) {
|
|
#define STRING_TYPE_CASE(TYPE, size, name, CamelName) case TYPE:
|
|
STRING_TYPE_LIST(STRING_TYPE_CASE)
|
|
#undef STRING_TYPE_CASE
|
|
String::cast(this)->StringVerify(isolate);
|
|
break;
|
|
case SYMBOL_TYPE:
|
|
Symbol::cast(this)->SymbolVerify(isolate);
|
|
break;
|
|
case MAP_TYPE:
|
|
Map::cast(this)->MapVerify(isolate);
|
|
break;
|
|
case HEAP_NUMBER_TYPE:
|
|
CHECK(IsHeapNumber());
|
|
break;
|
|
case MUTABLE_HEAP_NUMBER_TYPE:
|
|
CHECK(IsMutableHeapNumber());
|
|
break;
|
|
case BIGINT_TYPE:
|
|
BigInt::cast(this)->BigIntVerify(isolate);
|
|
break;
|
|
case CALL_HANDLER_INFO_TYPE:
|
|
CallHandlerInfo::cast(this)->CallHandlerInfoVerify(isolate);
|
|
break;
|
|
case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
|
|
ObjectBoilerplateDescription::cast(this)
|
|
->ObjectBoilerplateDescriptionVerify(isolate);
|
|
break;
|
|
case EMBEDDER_DATA_ARRAY_TYPE:
|
|
EmbedderDataArray::cast(this)->EmbedderDataArrayVerify(isolate);
|
|
break;
|
|
// FixedArray types
|
|
case HASH_TABLE_TYPE:
|
|
case ORDERED_HASH_MAP_TYPE:
|
|
case ORDERED_HASH_SET_TYPE:
|
|
case ORDERED_NAME_DICTIONARY_TYPE:
|
|
case NAME_DICTIONARY_TYPE:
|
|
case GLOBAL_DICTIONARY_TYPE:
|
|
case NUMBER_DICTIONARY_TYPE:
|
|
case SIMPLE_NUMBER_DICTIONARY_TYPE:
|
|
case STRING_TABLE_TYPE:
|
|
case EPHEMERON_HASH_TABLE_TYPE:
|
|
case FIXED_ARRAY_TYPE:
|
|
case SCOPE_INFO_TYPE:
|
|
case SCRIPT_CONTEXT_TABLE_TYPE:
|
|
FixedArray::cast(this)->FixedArrayVerify(isolate);
|
|
break;
|
|
case AWAIT_CONTEXT_TYPE:
|
|
case BLOCK_CONTEXT_TYPE:
|
|
case CATCH_CONTEXT_TYPE:
|
|
case DEBUG_EVALUATE_CONTEXT_TYPE:
|
|
case EVAL_CONTEXT_TYPE:
|
|
case FUNCTION_CONTEXT_TYPE:
|
|
case MODULE_CONTEXT_TYPE:
|
|
case SCRIPT_CONTEXT_TYPE:
|
|
case WITH_CONTEXT_TYPE:
|
|
Context::cast(this)->ContextVerify(isolate);
|
|
break;
|
|
case NATIVE_CONTEXT_TYPE:
|
|
NativeContext::cast(this)->NativeContextVerify(isolate);
|
|
break;
|
|
case WEAK_FIXED_ARRAY_TYPE:
|
|
WeakFixedArray::cast(this)->WeakFixedArrayVerify(isolate);
|
|
break;
|
|
case WEAK_ARRAY_LIST_TYPE:
|
|
WeakArrayList::cast(this)->WeakArrayListVerify(isolate);
|
|
break;
|
|
case FIXED_DOUBLE_ARRAY_TYPE:
|
|
FixedDoubleArray::cast(this)->FixedDoubleArrayVerify(isolate);
|
|
break;
|
|
case FEEDBACK_METADATA_TYPE:
|
|
FeedbackMetadata::cast(this)->FeedbackMetadataVerify(isolate);
|
|
break;
|
|
case BYTE_ARRAY_TYPE:
|
|
ByteArray::cast(this)->ByteArrayVerify(isolate);
|
|
break;
|
|
case BYTECODE_ARRAY_TYPE:
|
|
BytecodeArray::cast(this)->BytecodeArrayVerify(isolate);
|
|
break;
|
|
case DESCRIPTOR_ARRAY_TYPE:
|
|
DescriptorArray::cast(this)->DescriptorArrayVerify(isolate);
|
|
break;
|
|
case TRANSITION_ARRAY_TYPE:
|
|
TransitionArray::cast(this)->TransitionArrayVerify(isolate);
|
|
break;
|
|
case PROPERTY_ARRAY_TYPE:
|
|
PropertyArray::cast(this)->PropertyArrayVerify(isolate);
|
|
break;
|
|
case FREE_SPACE_TYPE:
|
|
FreeSpace::cast(this)->FreeSpaceVerify(isolate);
|
|
break;
|
|
case FEEDBACK_CELL_TYPE:
|
|
FeedbackCell::cast(this)->FeedbackCellVerify(isolate);
|
|
break;
|
|
case FEEDBACK_VECTOR_TYPE:
|
|
FeedbackVector::cast(this)->FeedbackVectorVerify(isolate);
|
|
break;
|
|
|
|
#define VERIFY_TYPED_ARRAY(Type, type, TYPE, ctype) \
|
|
case FIXED_##TYPE##_ARRAY_TYPE: \
|
|
Fixed##Type##Array::cast(this)->FixedTypedArrayVerify(isolate); \
|
|
break;
|
|
|
|
TYPED_ARRAYS(VERIFY_TYPED_ARRAY)
|
|
#undef VERIFY_TYPED_ARRAY
|
|
|
|
case CODE_TYPE:
|
|
Code::cast(this)->CodeVerify(isolate);
|
|
break;
|
|
case ODDBALL_TYPE:
|
|
Oddball::cast(this)->OddballVerify(isolate);
|
|
break;
|
|
case JS_OBJECT_TYPE:
|
|
case JS_ERROR_TYPE:
|
|
case JS_API_OBJECT_TYPE:
|
|
case JS_SPECIAL_API_OBJECT_TYPE:
|
|
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
|
|
case WASM_EXCEPTION_TYPE:
|
|
case WASM_GLOBAL_TYPE:
|
|
case WASM_MEMORY_TYPE:
|
|
case WASM_TABLE_TYPE:
|
|
JSObject::cast(this)->JSObjectVerify(isolate);
|
|
break;
|
|
case WASM_MODULE_TYPE:
|
|
WasmModuleObject::cast(this)->WasmModuleObjectVerify(isolate);
|
|
break;
|
|
case WASM_INSTANCE_TYPE:
|
|
WasmInstanceObject::cast(this)->WasmInstanceObjectVerify(isolate);
|
|
break;
|
|
case JS_ARGUMENTS_TYPE:
|
|
JSArgumentsObject::cast(this)->JSArgumentsObjectVerify(isolate);
|
|
break;
|
|
case JS_GENERATOR_OBJECT_TYPE:
|
|
JSGeneratorObject::cast(this)->JSGeneratorObjectVerify(isolate);
|
|
break;
|
|
case JS_ASYNC_FUNCTION_OBJECT_TYPE:
|
|
JSAsyncFunctionObject::cast(this)->JSAsyncFunctionObjectVerify(isolate);
|
|
break;
|
|
case JS_ASYNC_GENERATOR_OBJECT_TYPE:
|
|
JSAsyncGeneratorObject::cast(this)->JSAsyncGeneratorObjectVerify(isolate);
|
|
break;
|
|
case JS_VALUE_TYPE:
|
|
JSValue::cast(this)->JSValueVerify(isolate);
|
|
break;
|
|
case JS_DATE_TYPE:
|
|
JSDate::cast(this)->JSDateVerify(isolate);
|
|
break;
|
|
case JS_BOUND_FUNCTION_TYPE:
|
|
JSBoundFunction::cast(this)->JSBoundFunctionVerify(isolate);
|
|
break;
|
|
case JS_FUNCTION_TYPE:
|
|
JSFunction::cast(this)->JSFunctionVerify(isolate);
|
|
break;
|
|
case JS_GLOBAL_PROXY_TYPE:
|
|
JSGlobalProxy::cast(this)->JSGlobalProxyVerify(isolate);
|
|
break;
|
|
case JS_GLOBAL_OBJECT_TYPE:
|
|
JSGlobalObject::cast(this)->JSGlobalObjectVerify(isolate);
|
|
break;
|
|
case CELL_TYPE:
|
|
Cell::cast(this)->CellVerify(isolate);
|
|
break;
|
|
case PROPERTY_CELL_TYPE:
|
|
PropertyCell::cast(this)->PropertyCellVerify(isolate);
|
|
break;
|
|
case JS_ARRAY_TYPE:
|
|
JSArray::cast(this)->JSArrayVerify(isolate);
|
|
break;
|
|
case JS_MODULE_NAMESPACE_TYPE:
|
|
JSModuleNamespace::cast(this)->JSModuleNamespaceVerify(isolate);
|
|
break;
|
|
case JS_SET_TYPE:
|
|
JSSet::cast(this)->JSSetVerify(isolate);
|
|
break;
|
|
case JS_MAP_TYPE:
|
|
JSMap::cast(this)->JSMapVerify(isolate);
|
|
break;
|
|
case JS_SET_KEY_VALUE_ITERATOR_TYPE:
|
|
case JS_SET_VALUE_ITERATOR_TYPE:
|
|
JSSetIterator::cast(this)->JSSetIteratorVerify(isolate);
|
|
break;
|
|
case JS_MAP_KEY_ITERATOR_TYPE:
|
|
case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
|
|
case JS_MAP_VALUE_ITERATOR_TYPE:
|
|
JSMapIterator::cast(this)->JSMapIteratorVerify(isolate);
|
|
break;
|
|
case JS_ARRAY_ITERATOR_TYPE:
|
|
JSArrayIterator::cast(this)->JSArrayIteratorVerify(isolate);
|
|
break;
|
|
case JS_STRING_ITERATOR_TYPE:
|
|
JSStringIterator::cast(this)->JSStringIteratorVerify(isolate);
|
|
break;
|
|
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
|
|
JSAsyncFromSyncIterator::cast(this)->JSAsyncFromSyncIteratorVerify(
|
|
isolate);
|
|
break;
|
|
case JS_WEAK_CELL_TYPE:
|
|
case JS_WEAK_REF_TYPE:
|
|
JSWeakCell::cast(this)->JSWeakCellVerify(isolate);
|
|
break;
|
|
case JS_WEAK_FACTORY_TYPE:
|
|
JSWeakFactory::cast(this)->JSWeakFactoryVerify(isolate);
|
|
break;
|
|
case JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE:
|
|
JSWeakFactoryCleanupIterator::cast(this)
|
|
->JSWeakFactoryCleanupIteratorVerify(isolate);
|
|
break;
|
|
case JS_WEAK_MAP_TYPE:
|
|
JSWeakMap::cast(this)->JSWeakMapVerify(isolate);
|
|
break;
|
|
case JS_WEAK_SET_TYPE:
|
|
JSWeakSet::cast(this)->JSWeakSetVerify(isolate);
|
|
break;
|
|
case JS_PROMISE_TYPE:
|
|
JSPromise::cast(this)->JSPromiseVerify(isolate);
|
|
break;
|
|
case JS_REGEXP_TYPE:
|
|
JSRegExp::cast(this)->JSRegExpVerify(isolate);
|
|
break;
|
|
case JS_REGEXP_STRING_ITERATOR_TYPE:
|
|
JSRegExpStringIterator::cast(this)->JSRegExpStringIteratorVerify(isolate);
|
|
break;
|
|
case FILLER_TYPE:
|
|
break;
|
|
case JS_PROXY_TYPE:
|
|
JSProxy::cast(this)->JSProxyVerify(isolate);
|
|
break;
|
|
case FOREIGN_TYPE:
|
|
Foreign::cast(this)->ForeignVerify(isolate);
|
|
break;
|
|
case PRE_PARSED_SCOPE_DATA_TYPE:
|
|
PreParsedScopeData::cast(this)->PreParsedScopeDataVerify(isolate);
|
|
break;
|
|
case UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE:
|
|
UncompiledDataWithoutPreParsedScope::cast(this)
|
|
->UncompiledDataWithoutPreParsedScopeVerify(isolate);
|
|
break;
|
|
case UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE:
|
|
UncompiledDataWithPreParsedScope::cast(this)
|
|
->UncompiledDataWithPreParsedScopeVerify(isolate);
|
|
break;
|
|
case SHARED_FUNCTION_INFO_TYPE:
|
|
SharedFunctionInfo::cast(this)->SharedFunctionInfoVerify(isolate);
|
|
break;
|
|
case JS_MESSAGE_OBJECT_TYPE:
|
|
JSMessageObject::cast(this)->JSMessageObjectVerify(isolate);
|
|
break;
|
|
case JS_ARRAY_BUFFER_TYPE:
|
|
JSArrayBuffer::cast(this)->JSArrayBufferVerify(isolate);
|
|
break;
|
|
case JS_TYPED_ARRAY_TYPE:
|
|
JSTypedArray::cast(this)->JSTypedArrayVerify(isolate);
|
|
break;
|
|
case JS_DATA_VIEW_TYPE:
|
|
JSDataView::cast(this)->JSDataViewVerify(isolate);
|
|
break;
|
|
case SMALL_ORDERED_HASH_SET_TYPE:
|
|
SmallOrderedHashSet::cast(this)->SmallOrderedHashTableVerify(isolate);
|
|
break;
|
|
case SMALL_ORDERED_HASH_MAP_TYPE:
|
|
SmallOrderedHashMap::cast(this)->SmallOrderedHashTableVerify(isolate);
|
|
break;
|
|
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
|
|
SmallOrderedNameDictionary::cast(this)->SmallOrderedHashTableVerify(
|
|
isolate);
|
|
break;
|
|
case CODE_DATA_CONTAINER_TYPE:
|
|
CodeDataContainer::cast(this)->CodeDataContainerVerify(isolate);
|
|
break;
|
|
#ifdef V8_INTL_SUPPORT
|
|
case JS_INTL_V8_BREAK_ITERATOR_TYPE:
|
|
JSV8BreakIterator::cast(this)->JSV8BreakIteratorVerify(isolate);
|
|
break;
|
|
case JS_INTL_COLLATOR_TYPE:
|
|
JSCollator::cast(this)->JSCollatorVerify(isolate);
|
|
break;
|
|
case JS_INTL_DATE_TIME_FORMAT_TYPE:
|
|
JSDateTimeFormat::cast(this)->JSDateTimeFormatVerify(isolate);
|
|
break;
|
|
case JS_INTL_LIST_FORMAT_TYPE:
|
|
JSListFormat::cast(this)->JSListFormatVerify(isolate);
|
|
break;
|
|
case JS_INTL_LOCALE_TYPE:
|
|
JSLocale::cast(this)->JSLocaleVerify(isolate);
|
|
break;
|
|
case JS_INTL_NUMBER_FORMAT_TYPE:
|
|
JSNumberFormat::cast(this)->JSNumberFormatVerify(isolate);
|
|
break;
|
|
case JS_INTL_PLURAL_RULES_TYPE:
|
|
JSPluralRules::cast(this)->JSPluralRulesVerify(isolate);
|
|
break;
|
|
case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
|
|
JSRelativeTimeFormat::cast(this)->JSRelativeTimeFormatVerify(isolate);
|
|
break;
|
|
case JS_INTL_SEGMENT_ITERATOR_TYPE:
|
|
JSSegmentIterator::cast(this)->JSSegmentIteratorVerify(isolate);
|
|
break;
|
|
case JS_INTL_SEGMENTER_TYPE:
|
|
JSSegmenter::cast(this)->JSSegmenterVerify(isolate);
|
|
break;
|
|
#endif // V8_INTL_SUPPORT
|
|
|
|
#define MAKE_STRUCT_CASE(TYPE, Name, name) \
|
|
case TYPE: \
|
|
Name::cast(this)->Name##Verify(isolate); \
|
|
break;
|
|
STRUCT_LIST(MAKE_STRUCT_CASE)
|
|
#undef MAKE_STRUCT_CASE
|
|
|
|
case ALLOCATION_SITE_TYPE:
|
|
AllocationSite::cast(this)->AllocationSiteVerify(isolate);
|
|
break;
|
|
|
|
case LOAD_HANDLER_TYPE:
|
|
LoadHandler::cast(this)->LoadHandlerVerify(isolate);
|
|
break;
|
|
|
|
case STORE_HANDLER_TYPE:
|
|
StoreHandler::cast(this)->StoreHandlerVerify(isolate);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void HeapObjectPtr::HeapObjectVerify(Isolate* isolate) {
|
|
reinterpret_cast<HeapObject*>(ptr())->HeapObjectVerify(isolate);
|
|
}
|
|
|
|
void HeapObject::VerifyHeapPointer(Isolate* isolate, Object* p) {
|
|
CHECK(p->IsHeapObject());
|
|
HeapObject* ho = HeapObject::cast(p);
|
|
CHECK(isolate->heap()->Contains(ho));
|
|
}
|
|
|
|
void HeapObjectPtr::VerifyHeapPointer(Isolate* isolate, Object* p) {
|
|
HeapObject::VerifyHeapPointer(isolate, p);
|
|
}
|
|
|
|
void Symbol::SymbolVerify(Isolate* isolate) {
|
|
CHECK(IsSymbol());
|
|
CHECK(HasHashCode());
|
|
CHECK_GT(Hash(), 0);
|
|
CHECK(name()->IsUndefined(isolate) || name()->IsString());
|
|
CHECK_IMPLIES(IsPrivateName(), IsPrivate());
|
|
}
|
|
|
|
void ByteArray::ByteArrayVerify(Isolate* isolate) { CHECK(IsByteArray()); }
|
|
|
|
void BytecodeArray::BytecodeArrayVerify(Isolate* isolate) {
|
|
// TODO(oth): Walk bytecodes and immediate values to validate sanity.
|
|
// - All bytecodes are known and well formed.
|
|
// - Jumps must go to new instructions starts.
|
|
// - No Illegal bytecodes.
|
|
// - No consecutive sequences of prefix Wide / ExtraWide.
|
|
CHECK(IsBytecodeArray());
|
|
CHECK(constant_pool()->IsFixedArray());
|
|
VerifyHeapPointer(isolate, constant_pool());
|
|
}
|
|
|
|
void FreeSpace::FreeSpaceVerify(Isolate* isolate) { CHECK(IsFreeSpace()); }
|
|
|
|
void FeedbackCell::FeedbackCellVerify(Isolate* isolate) {
|
|
CHECK(IsFeedbackCell());
|
|
|
|
VerifyHeapPointer(isolate, value());
|
|
CHECK(value()->IsUndefined(isolate) || value()->IsFeedbackVector());
|
|
}
|
|
|
|
void FeedbackVector::FeedbackVectorVerify(Isolate* isolate) {
|
|
CHECK(IsFeedbackVector());
|
|
MaybeObject code = optimized_code_weak_or_smi();
|
|
MaybeObject::VerifyMaybeObjectPointer(isolate, code);
|
|
CHECK(code->IsSmi() || code->IsWeakOrCleared());
|
|
}
|
|
|
|
template <class Traits>
|
|
void FixedTypedArray<Traits>::FixedTypedArrayVerify(Isolate* isolate) {
|
|
CHECK(IsHeapObject() && map()->instance_type() == Traits::kInstanceType);
|
|
if (base_pointer()->ptr() == ptr()) {
|
|
CHECK(reinterpret_cast<Address>(external_pointer()) ==
|
|
ExternalReference::fixed_typed_array_base_data_offset().address());
|
|
} else {
|
|
CHECK_EQ(base_pointer(), Smi::kZero);
|
|
}
|
|
}
|
|
|
|
bool JSObject::ElementsAreSafeToExamine() const {
|
|
// If a GC was caused while constructing this object, the elements
|
|
// pointer may point to a one pointer filler map.
|
|
return elements() != GetReadOnlyRoots().one_pointer_filler_map();
|
|
}
|
|
|
|
namespace {
|
|
void VerifyJSObjectElements(Isolate* isolate, JSObject object) {
|
|
// Only TypedArrays can have these specialized elements.
|
|
if (object->IsJSTypedArray()) {
|
|
// TODO(cbruni): Fix CreateTypedArray to either not instantiate the object
|
|
// or propertly initialize it on errors during construction.
|
|
/* CHECK(object->HasFixedTypedArrayElements()); */
|
|
/* CHECK(object->elements()->IsFixedTypedArrayBase()); */
|
|
return;
|
|
}
|
|
CHECK(!object->HasFixedTypedArrayElements());
|
|
CHECK(!object->elements()->IsFixedTypedArrayBase());
|
|
|
|
if (object->HasDoubleElements()) {
|
|
if (object->elements()->length() > 0) {
|
|
CHECK(object->elements()->IsFixedDoubleArray());
|
|
}
|
|
return;
|
|
}
|
|
|
|
FixedArray elements = FixedArray::cast(object->elements());
|
|
if (object->HasSmiElements()) {
|
|
// We might have a partially initialized backing store, in which case we
|
|
// allow the hole + smi values.
|
|
for (int i = 0; i < elements->length(); i++) {
|
|
Object* value = elements->get(i);
|
|
CHECK(value->IsSmi() || value->IsTheHole(isolate));
|
|
}
|
|
} else if (object->HasObjectElements()) {
|
|
for (int i = 0; i < elements->length(); i++) {
|
|
Object* element = elements->get(i);
|
|
CHECK_IMPLIES(!element->IsSmi(), !HasWeakHeapObjectTag(element));
|
|
}
|
|
}
|
|
}
|
|
} // namespace
|
|
|
|
void JSObject::JSObjectVerify(Isolate* isolate) {
|
|
VerifyPointer(isolate, raw_properties_or_hash());
|
|
VerifyHeapPointer(isolate, elements());
|
|
|
|
CHECK_IMPLIES(HasSloppyArgumentsElements(), IsJSArgumentsObject());
|
|
if (HasFastProperties()) {
|
|
int actual_unused_property_fields = map()->GetInObjectProperties() +
|
|
property_array()->length() -
|
|
map()->NextFreePropertyIndex();
|
|
if (map()->UnusedPropertyFields() != actual_unused_property_fields) {
|
|
// There are two reasons why this can 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 while the map isn't updated yet.
|
|
// - deletion of the last property can leave additional backing store
|
|
// capacity behind.
|
|
CHECK_GT(actual_unused_property_fields, map()->UnusedPropertyFields());
|
|
int delta = actual_unused_property_fields - map()->UnusedPropertyFields();
|
|
CHECK_EQ(0, delta % JSObject::kFieldsAdded);
|
|
}
|
|
DescriptorArray descriptors = map()->instance_descriptors();
|
|
bool is_transitionable_fast_elements_kind =
|
|
IsTransitionableFastElementsKind(map()->elements_kind());
|
|
|
|
for (int i = 0; i < map()->NumberOfOwnDescriptors(); i++) {
|
|
PropertyDetails details = descriptors->GetDetails(i);
|
|
if (details.location() == kField) {
|
|
DCHECK_EQ(kData, details.kind());
|
|
Representation r = details.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())) {
|
|
CHECK(!field_type->NowStable() || field_type->NowContains(value));
|
|
}
|
|
CHECK_IMPLIES(is_transitionable_fast_elements_kind,
|
|
!Map::IsInplaceGeneralizableField(details.constness(), r,
|
|
field_type));
|
|
}
|
|
}
|
|
|
|
if (map()->EnumLength() != kInvalidEnumCacheSentinel) {
|
|
EnumCache* enum_cache = descriptors->enum_cache();
|
|
FixedArray keys = enum_cache->keys();
|
|
FixedArray indices = enum_cache->indices();
|
|
CHECK_LE(map()->EnumLength(), keys->length());
|
|
CHECK_IMPLIES(indices != ReadOnlyRoots(isolate).empty_fixed_array(),
|
|
keys->length() == indices->length());
|
|
}
|
|
}
|
|
|
|
// 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() == GetReadOnlyRoots().empty_fixed_array()) ||
|
|
HasFastStringWrapperElements()),
|
|
(elements()->map() == GetReadOnlyRoots().fixed_array_map() ||
|
|
elements()->map() == GetReadOnlyRoots().fixed_cow_array_map()));
|
|
CHECK_EQ(map()->has_fast_object_elements(), HasObjectElements());
|
|
VerifyJSObjectElements(isolate, *this);
|
|
}
|
|
}
|
|
|
|
void Map::MapVerify(Isolate* isolate) {
|
|
Heap* heap = isolate->heap();
|
|
CHECK(!Heap::InNewSpace(*this));
|
|
CHECK(FIRST_TYPE <= instance_type() && instance_type() <= LAST_TYPE);
|
|
CHECK(instance_size() == kVariableSizeSentinel ||
|
|
(kPointerSize <= instance_size() &&
|
|
static_cast<size_t>(instance_size()) < heap->Capacity()));
|
|
CHECK(GetBackPointer()->IsUndefined(heap->isolate()) ||
|
|
!Map::cast(GetBackPointer())->is_stable());
|
|
HeapObject::VerifyHeapPointer(isolate, prototype());
|
|
HeapObject::VerifyHeapPointer(isolate, instance_descriptors());
|
|
SLOW_DCHECK(instance_descriptors()->IsSortedNoDuplicates());
|
|
DisallowHeapAllocation no_gc;
|
|
SLOW_DCHECK(
|
|
TransitionsAccessor(isolate, *this, &no_gc).IsSortedNoDuplicates());
|
|
SLOW_DCHECK(TransitionsAccessor(isolate, *this, &no_gc)
|
|
.IsConsistentWithBackPointers());
|
|
SLOW_DCHECK(!FLAG_unbox_double_fields ||
|
|
layout_descriptor()->IsConsistentWithMap(*this));
|
|
if (!may_have_interesting_symbols()) {
|
|
CHECK(!has_named_interceptor());
|
|
CHECK(!is_dictionary_map());
|
|
CHECK(!is_access_check_needed());
|
|
DescriptorArray const descriptors = instance_descriptors();
|
|
for (int i = 0; i < NumberOfOwnDescriptors(); ++i) {
|
|
CHECK(!descriptors->GetKey(i)->IsInterestingSymbol());
|
|
}
|
|
}
|
|
CHECK_IMPLIES(has_named_interceptor(), may_have_interesting_symbols());
|
|
CHECK_IMPLIES(is_dictionary_map(), may_have_interesting_symbols());
|
|
CHECK_IMPLIES(is_access_check_needed(), may_have_interesting_symbols());
|
|
CHECK_IMPLIES(IsJSObjectMap() && !CanHaveFastTransitionableElementsKind(),
|
|
IsDictionaryElementsKind(elements_kind()) ||
|
|
IsTerminalElementsKind(elements_kind()));
|
|
if (is_prototype_map()) {
|
|
DCHECK(prototype_info() == Smi::kZero ||
|
|
prototype_info()->IsPrototypeInfo());
|
|
}
|
|
CHECK(prototype_validity_cell()->IsSmi() ||
|
|
prototype_validity_cell()->IsCell());
|
|
}
|
|
|
|
void Map::DictionaryMapVerify(Isolate* isolate) {
|
|
MapVerify(isolate);
|
|
CHECK(is_dictionary_map());
|
|
CHECK_EQ(kInvalidEnumCacheSentinel, EnumLength());
|
|
CHECK_EQ(ReadOnlyRoots(isolate).empty_descriptor_array(),
|
|
instance_descriptors());
|
|
CHECK_EQ(0, UnusedPropertyFields());
|
|
CHECK_EQ(Map::GetVisitorId(*this), visitor_id());
|
|
}
|
|
|
|
void AliasedArgumentsEntry::AliasedArgumentsEntryVerify(Isolate* isolate) {
|
|
VerifySmiField(kAliasedContextSlot);
|
|
}
|
|
|
|
void EmbedderDataArray::EmbedderDataArrayVerify(Isolate* isolate) {
|
|
EmbedderDataSlot start(*this, 0);
|
|
EmbedderDataSlot end(*this, length());
|
|
for (EmbedderDataSlot slot = start; slot < end; ++slot) {
|
|
Object* e = slot.load_tagged();
|
|
Object::VerifyPointer(isolate, e);
|
|
}
|
|
}
|
|
|
|
void FixedArray::FixedArrayVerify(Isolate* isolate) {
|
|
for (int i = 0; i < length(); i++) {
|
|
Object* e = get(i);
|
|
VerifyPointer(isolate, e);
|
|
}
|
|
}
|
|
|
|
void WeakFixedArray::WeakFixedArrayVerify(Isolate* isolate) {
|
|
for (int i = 0; i < length(); i++) {
|
|
MaybeObject::VerifyMaybeObjectPointer(isolate, Get(i));
|
|
}
|
|
}
|
|
|
|
void WeakArrayList::WeakArrayListVerify(Isolate* isolate) {
|
|
for (int i = 0; i < length(); i++) {
|
|
MaybeObject::VerifyMaybeObjectPointer(isolate, Get(i));
|
|
}
|
|
}
|
|
|
|
void PropertyArray::PropertyArrayVerify(Isolate* isolate) {
|
|
if (length() == 0) {
|
|
CHECK_EQ(*this, ReadOnlyRoots(isolate).empty_property_array());
|
|
return;
|
|
}
|
|
// There are no empty PropertyArrays.
|
|
CHECK_LT(0, length());
|
|
for (int i = 0; i < length(); i++) {
|
|
Object* e = get(i);
|
|
Object::VerifyPointer(isolate, e);
|
|
}
|
|
}
|
|
|
|
void FixedDoubleArray::FixedDoubleArrayVerify(Isolate* isolate) {
|
|
for (int i = 0; i < length(); i++) {
|
|
if (!is_the_hole(i)) {
|
|
uint64_t value = get_representation(i);
|
|
uint64_t unexpected =
|
|
bit_cast<uint64_t>(std::numeric_limits<double>::quiet_NaN()) &
|
|
uint64_t{0x7FF8000000000000};
|
|
// Create implementation specific sNaN by inverting relevant bit.
|
|
unexpected ^= uint64_t{0x0008000000000000};
|
|
CHECK((value & uint64_t{0x7FF8000000000000}) != unexpected ||
|
|
(value & uint64_t{0x0007FFFFFFFFFFFF}) == uint64_t{0});
|
|
}
|
|
}
|
|
}
|
|
|
|
void Context::ContextVerify(Isolate* isolate) {
|
|
VerifySmiField(kLengthOffset);
|
|
VerifyObjectField(isolate, kScopeInfoOffset);
|
|
VerifyObjectField(isolate, kPreviousOffset);
|
|
VerifyObjectField(isolate, kExtensionOffset);
|
|
VerifyObjectField(isolate, kNativeContextOffset);
|
|
for (int i = 0; i < length(); i++) {
|
|
VerifyObjectField(isolate, OffsetOfElementAt(i));
|
|
}
|
|
}
|
|
|
|
void NativeContext::NativeContextVerify(Isolate* isolate) {
|
|
ContextVerify(isolate);
|
|
CHECK_EQ(length(), NativeContext::NATIVE_CONTEXT_SLOTS);
|
|
CHECK_EQ(kSize, map()->instance_size());
|
|
}
|
|
|
|
void FeedbackMetadata::FeedbackMetadataVerify(Isolate* isolate) {
|
|
if (slot_count() == 0) {
|
|
CHECK_EQ(ReadOnlyRoots(isolate).empty_feedback_metadata(), *this);
|
|
} else {
|
|
FeedbackMetadataIterator iter(*this);
|
|
while (iter.HasNext()) {
|
|
iter.Next();
|
|
FeedbackSlotKind kind = iter.kind();
|
|
CHECK_NE(FeedbackSlotKind::kInvalid, kind);
|
|
CHECK_GT(FeedbackSlotKind::kKindsNumber, kind);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DescriptorArray::DescriptorArrayVerify(Isolate* isolate) {
|
|
for (int i = 0; i < number_of_all_descriptors(); i++) {
|
|
MaybeObject::VerifyMaybeObjectPointer(isolate, get(ToKeyIndex(i)));
|
|
MaybeObject::VerifyMaybeObjectPointer(isolate, get(ToDetailsIndex(i)));
|
|
MaybeObject::VerifyMaybeObjectPointer(isolate, get(ToValueIndex(i)));
|
|
}
|
|
if (number_of_all_descriptors() == 0) {
|
|
Heap* heap = isolate->heap();
|
|
CHECK_EQ(ReadOnlyRoots(heap).empty_descriptor_array(), *this);
|
|
CHECK_EQ(0, number_of_all_descriptors());
|
|
CHECK_EQ(0, number_of_descriptors());
|
|
CHECK_EQ(ReadOnlyRoots(heap).empty_enum_cache(), enum_cache());
|
|
} else {
|
|
CHECK_LT(0, number_of_all_descriptors());
|
|
CHECK_LE(number_of_descriptors(), number_of_all_descriptors());
|
|
|
|
// Check that properties with private symbols names are non-enumerable.
|
|
for (int descriptor = 0; descriptor < number_of_descriptors();
|
|
descriptor++) {
|
|
Object* key = get(ToKeyIndex(descriptor))->cast<Object>();
|
|
// number_of_descriptors() may be out of sync with the actual descriptors
|
|
// written during descriptor array construction.
|
|
if (key->IsUndefined(isolate)) continue;
|
|
PropertyDetails details = GetDetails(descriptor);
|
|
if (Name::cast(key)->IsPrivate()) {
|
|
CHECK_NE(details.attributes() & DONT_ENUM, 0);
|
|
}
|
|
MaybeObject value = get(ToValueIndex(descriptor));
|
|
HeapObject* heap_object;
|
|
if (details.location() == kField) {
|
|
CHECK(
|
|
value == MaybeObject::FromObject(FieldType::None()) ||
|
|
value == MaybeObject::FromObject(FieldType::Any()) ||
|
|
value->IsCleared() ||
|
|
(value->GetHeapObjectIfWeak(&heap_object) && heap_object->IsMap()));
|
|
} else {
|
|
CHECK(!value->IsWeakOrCleared());
|
|
CHECK(!value->cast<Object>()->IsMap());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TransitionArray::TransitionArrayVerify(Isolate* isolate) {
|
|
WeakFixedArrayVerify(isolate);
|
|
CHECK_LE(LengthFor(number_of_transitions()), length());
|
|
}
|
|
|
|
void JSArgumentsObject::JSArgumentsObjectVerify(Isolate* isolate) {
|
|
if (IsSloppyArgumentsElementsKind(GetElementsKind())) {
|
|
SloppyArgumentsElements::cast(elements())
|
|
->SloppyArgumentsElementsVerify(isolate, *this);
|
|
}
|
|
if (isolate->IsInAnyContext(map(), Context::SLOPPY_ARGUMENTS_MAP_INDEX) ||
|
|
isolate->IsInAnyContext(map(),
|
|
Context::SLOW_ALIASED_ARGUMENTS_MAP_INDEX) ||
|
|
isolate->IsInAnyContext(map(),
|
|
Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX)) {
|
|
VerifyObjectField(isolate, JSSloppyArgumentsObject::kLengthOffset);
|
|
VerifyObjectField(isolate, JSSloppyArgumentsObject::kCalleeOffset);
|
|
} else if (isolate->IsInAnyContext(map(),
|
|
Context::STRICT_ARGUMENTS_MAP_INDEX)) {
|
|
VerifyObjectField(isolate, JSStrictArgumentsObject::kLengthOffset);
|
|
}
|
|
JSObjectVerify(isolate);
|
|
}
|
|
|
|
void SloppyArgumentsElements::SloppyArgumentsElementsVerify(Isolate* isolate,
|
|
JSObject holder) {
|
|
FixedArrayVerify(isolate);
|
|
// Abort verification if only partially initialized (can't use arguments()
|
|
// getter because it does FixedArray::cast()).
|
|
if (get(kArgumentsIndex)->IsUndefined(isolate)) return;
|
|
|
|
ElementsKind kind = holder->GetElementsKind();
|
|
bool is_fast = kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
|
|
CHECK(IsFixedArray());
|
|
CHECK_GE(length(), 2);
|
|
CHECK_EQ(map(), ReadOnlyRoots(isolate).sloppy_arguments_elements_map());
|
|
Context context_object = context();
|
|
FixedArray arg_elements = FixedArray::cast(arguments());
|
|
if (arg_elements->length() == 0) {
|
|
CHECK(arg_elements == ReadOnlyRoots(isolate).empty_fixed_array());
|
|
return;
|
|
}
|
|
ElementsAccessor* accessor;
|
|
if (is_fast) {
|
|
accessor = ElementsAccessor::ForKind(HOLEY_ELEMENTS);
|
|
} else {
|
|
accessor = ElementsAccessor::ForKind(DICTIONARY_ELEMENTS);
|
|
}
|
|
int nofMappedParameters = 0;
|
|
int maxMappedIndex = 0;
|
|
for (int i = 0; i < nofMappedParameters; i++) {
|
|
// Verify that each context-mapped argument is either the hole or a valid
|
|
// Smi within context length range.
|
|
Object* mapped = get_mapped_entry(i);
|
|
if (mapped->IsTheHole(isolate)) {
|
|
// Slow sloppy arguments can be holey.
|
|
if (!is_fast) continue;
|
|
// Fast sloppy arguments elements are never holey. Either the element is
|
|
// context-mapped or present in the arguments elements.
|
|
CHECK(accessor->HasElement(holder, i, arg_elements));
|
|
continue;
|
|
}
|
|
int mappedIndex = Smi::ToInt(mapped);
|
|
nofMappedParameters++;
|
|
CHECK_LE(maxMappedIndex, mappedIndex);
|
|
maxMappedIndex = mappedIndex;
|
|
Object* value = context_object->get(mappedIndex);
|
|
CHECK(value->IsObject());
|
|
// None of the context-mapped entries should exist in the arguments
|
|
// elements.
|
|
CHECK(!accessor->HasElement(holder, i, arg_elements));
|
|
}
|
|
CHECK_LE(nofMappedParameters, context_object->length());
|
|
CHECK_LE(nofMappedParameters, arg_elements->length());
|
|
CHECK_LE(maxMappedIndex, context_object->length());
|
|
CHECK_LE(maxMappedIndex, arg_elements->length());
|
|
}
|
|
|
|
void JSGeneratorObject::JSGeneratorObjectVerify(Isolate* isolate) {
|
|
// In an expression like "new g()", there can be a point where a generator
|
|
// object is allocated but its fields are all undefined, as it hasn't yet been
|
|
// initialized by the generator. Hence these weak checks.
|
|
VerifyObjectField(isolate, kFunctionOffset);
|
|
VerifyObjectField(isolate, kContextOffset);
|
|
VerifyObjectField(isolate, kReceiverOffset);
|
|
VerifyObjectField(isolate, kParametersAndRegistersOffset);
|
|
VerifyObjectField(isolate, kContinuationOffset);
|
|
}
|
|
|
|
void JSAsyncFunctionObject::JSAsyncFunctionObjectVerify(Isolate* isolate) {
|
|
// Check inherited fields
|
|
JSGeneratorObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kPromiseOffset);
|
|
promise()->HeapObjectVerify(isolate);
|
|
}
|
|
|
|
void JSAsyncGeneratorObject::JSAsyncGeneratorObjectVerify(Isolate* isolate) {
|
|
// Check inherited fields
|
|
JSGeneratorObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kQueueOffset);
|
|
queue()->HeapObjectVerify(isolate);
|
|
}
|
|
|
|
void JSValue::JSValueVerify(Isolate* isolate) {
|
|
Object* v = value();
|
|
if (v->IsHeapObject()) {
|
|
VerifyHeapPointer(isolate, v);
|
|
}
|
|
}
|
|
|
|
void JSDate::JSDateVerify(Isolate* isolate) {
|
|
if (value()->IsHeapObject()) {
|
|
VerifyHeapPointer(isolate, value());
|
|
}
|
|
CHECK(value()->IsUndefined(isolate) || value()->IsSmi() ||
|
|
value()->IsHeapNumber());
|
|
CHECK(year()->IsUndefined(isolate) || year()->IsSmi() || year()->IsNaN());
|
|
CHECK(month()->IsUndefined(isolate) || month()->IsSmi() || month()->IsNaN());
|
|
CHECK(day()->IsUndefined(isolate) || day()->IsSmi() || day()->IsNaN());
|
|
CHECK(weekday()->IsUndefined(isolate) || weekday()->IsSmi() ||
|
|
weekday()->IsNaN());
|
|
CHECK(hour()->IsUndefined(isolate) || hour()->IsSmi() || hour()->IsNaN());
|
|
CHECK(min()->IsUndefined(isolate) || min()->IsSmi() || min()->IsNaN());
|
|
CHECK(sec()->IsUndefined(isolate) || sec()->IsSmi() || sec()->IsNaN());
|
|
CHECK(cache_stamp()->IsUndefined(isolate) || cache_stamp()->IsSmi() ||
|
|
cache_stamp()->IsNaN());
|
|
|
|
if (month()->IsSmi()) {
|
|
int month = Smi::ToInt(this->month());
|
|
CHECK(0 <= month && month <= 11);
|
|
}
|
|
if (day()->IsSmi()) {
|
|
int day = Smi::ToInt(this->day());
|
|
CHECK(1 <= day && day <= 31);
|
|
}
|
|
if (hour()->IsSmi()) {
|
|
int hour = Smi::ToInt(this->hour());
|
|
CHECK(0 <= hour && hour <= 23);
|
|
}
|
|
if (min()->IsSmi()) {
|
|
int min = Smi::ToInt(this->min());
|
|
CHECK(0 <= min && min <= 59);
|
|
}
|
|
if (sec()->IsSmi()) {
|
|
int sec = Smi::ToInt(this->sec());
|
|
CHECK(0 <= sec && sec <= 59);
|
|
}
|
|
if (weekday()->IsSmi()) {
|
|
int weekday = Smi::ToInt(this->weekday());
|
|
CHECK(0 <= weekday && weekday <= 6);
|
|
}
|
|
if (cache_stamp()->IsSmi()) {
|
|
CHECK(Smi::ToInt(cache_stamp()) <=
|
|
Smi::ToInt(isolate->date_cache()->stamp()));
|
|
}
|
|
}
|
|
|
|
void JSMessageObject::JSMessageObjectVerify(Isolate* isolate) {
|
|
CHECK(IsJSMessageObject());
|
|
VerifyObjectField(isolate, kStartPositionOffset);
|
|
VerifyObjectField(isolate, kEndPositionOffset);
|
|
VerifyObjectField(isolate, kArgumentsOffset);
|
|
VerifyObjectField(isolate, kScriptOffset);
|
|
VerifyObjectField(isolate, kStackFramesOffset);
|
|
}
|
|
|
|
void String::StringVerify(Isolate* isolate) {
|
|
CHECK(IsString());
|
|
CHECK(length() >= 0 && length() <= Smi::kMaxValue);
|
|
CHECK_IMPLIES(length() == 0, *this == ReadOnlyRoots(isolate).empty_string());
|
|
if (IsInternalizedString()) {
|
|
CHECK(!Heap::InNewSpace(*this));
|
|
}
|
|
if (IsConsString()) {
|
|
ConsString::cast(*this)->ConsStringVerify(isolate);
|
|
} else if (IsSlicedString()) {
|
|
SlicedString::cast(*this)->SlicedStringVerify(isolate);
|
|
} else if (IsThinString()) {
|
|
ThinString::cast(*this)->ThinStringVerify(isolate);
|
|
}
|
|
}
|
|
|
|
void ConsString::ConsStringVerify(Isolate* isolate) {
|
|
CHECK(this->first()->IsString());
|
|
CHECK(this->second() == ReadOnlyRoots(isolate).empty_string() ||
|
|
this->second()->IsString());
|
|
CHECK_GE(this->length(), ConsString::kMinLength);
|
|
CHECK(this->length() == this->first()->length() + this->second()->length());
|
|
if (this->IsFlat()) {
|
|
// A flat cons can only be created by String::SlowFlatten.
|
|
// Afterwards, the first part may be externalized or internalized.
|
|
CHECK(this->first()->IsSeqString() || this->first()->IsExternalString() ||
|
|
this->first()->IsThinString());
|
|
}
|
|
}
|
|
|
|
void ThinString::ThinStringVerify(Isolate* isolate) {
|
|
CHECK(this->actual()->IsInternalizedString());
|
|
CHECK(this->actual()->IsSeqString() || this->actual()->IsExternalString());
|
|
}
|
|
|
|
void SlicedString::SlicedStringVerify(Isolate* isolate) {
|
|
CHECK(!this->parent()->IsConsString());
|
|
CHECK(!this->parent()->IsSlicedString());
|
|
CHECK_GE(this->length(), SlicedString::kMinLength);
|
|
}
|
|
|
|
void JSBoundFunction::JSBoundFunctionVerify(Isolate* isolate) {
|
|
CHECK(IsJSBoundFunction());
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kBoundThisOffset);
|
|
VerifyObjectField(isolate, kBoundTargetFunctionOffset);
|
|
VerifyObjectField(isolate, kBoundArgumentsOffset);
|
|
CHECK(IsCallable());
|
|
|
|
if (!raw_bound_target_function()->IsUndefined(isolate)) {
|
|
CHECK(bound_target_function()->IsCallable());
|
|
CHECK_EQ(IsConstructor(), bound_target_function()->IsConstructor());
|
|
}
|
|
}
|
|
|
|
void JSFunction::JSFunctionVerify(Isolate* isolate) {
|
|
CHECK(IsJSFunction());
|
|
JSObjectVerify(isolate);
|
|
VerifyHeapPointer(isolate, raw_feedback_cell());
|
|
CHECK(raw_feedback_cell()->IsFeedbackCell());
|
|
CHECK(code()->IsCode());
|
|
CHECK(map()->is_callable());
|
|
Handle<JSFunction> function(*this, isolate);
|
|
LookupIterator it(isolate, function, isolate->factory()->prototype_string(),
|
|
LookupIterator::OWN_SKIP_INTERCEPTOR);
|
|
if (has_prototype_slot()) {
|
|
VerifyObjectField(isolate, kPrototypeOrInitialMapOffset);
|
|
}
|
|
|
|
if (has_prototype_property()) {
|
|
CHECK(it.IsFound());
|
|
CHECK_EQ(LookupIterator::ACCESSOR, it.state());
|
|
CHECK(it.GetAccessors()->IsAccessorInfo());
|
|
} else {
|
|
CHECK(!it.IsFound() || it.state() != LookupIterator::ACCESSOR ||
|
|
!it.GetAccessors()->IsAccessorInfo());
|
|
}
|
|
}
|
|
|
|
void SharedFunctionInfo::SharedFunctionInfoVerify(Isolate* isolate) {
|
|
CHECK(IsSharedFunctionInfo());
|
|
|
|
VerifyObjectField(isolate, kFunctionDataOffset);
|
|
VerifyObjectField(isolate, kOuterScopeInfoOrFeedbackMetadataOffset);
|
|
VerifyObjectField(isolate, kScriptOrDebugInfoOffset);
|
|
VerifyObjectField(isolate, kNameOrScopeInfoOffset);
|
|
|
|
Object* value = name_or_scope_info();
|
|
CHECK(value == kNoSharedNameSentinel || value->IsString() ||
|
|
value->IsScopeInfo());
|
|
if (value->IsScopeInfo()) {
|
|
CHECK_LT(0, ScopeInfo::cast(value)->length());
|
|
CHECK_NE(value, ReadOnlyRoots(isolate).empty_scope_info());
|
|
}
|
|
|
|
CHECK(HasWasmExportedFunctionData() || IsApiFunction() ||
|
|
HasBytecodeArray() || HasAsmWasmData() || HasBuiltinId() ||
|
|
HasUncompiledDataWithPreParsedScope() ||
|
|
HasUncompiledDataWithoutPreParsedScope());
|
|
|
|
CHECK(script_or_debug_info()->IsUndefined(isolate) ||
|
|
script_or_debug_info()->IsScript() || HasDebugInfo());
|
|
|
|
if (!is_compiled()) {
|
|
CHECK(!HasFeedbackMetadata());
|
|
CHECK(outer_scope_info()->IsScopeInfo() ||
|
|
outer_scope_info()->IsTheHole(isolate));
|
|
} else if (HasBytecodeArray()) {
|
|
CHECK(HasFeedbackMetadata());
|
|
CHECK(feedback_metadata()->IsFeedbackMetadata());
|
|
}
|
|
|
|
int expected_map_index = Context::FunctionMapIndex(
|
|
language_mode(), kind(), true, HasSharedName(), needs_home_object());
|
|
CHECK_EQ(expected_map_index, function_map_index());
|
|
|
|
if (scope_info()->length() > 0) {
|
|
ScopeInfo info = scope_info();
|
|
CHECK(kind() == info->function_kind());
|
|
CHECK_EQ(kind() == kModule, info->scope_type() == MODULE_SCOPE);
|
|
}
|
|
|
|
if (IsApiFunction()) {
|
|
CHECK(construct_as_builtin());
|
|
} else if (!HasBuiltinId()) {
|
|
CHECK(!construct_as_builtin());
|
|
} else {
|
|
int id = builtin_id();
|
|
if (id != Builtins::kCompileLazy && id != Builtins::kEmptyFunction) {
|
|
CHECK(construct_as_builtin());
|
|
} else {
|
|
CHECK(!construct_as_builtin());
|
|
}
|
|
}
|
|
}
|
|
|
|
void JSGlobalProxy::JSGlobalProxyVerify(Isolate* isolate) {
|
|
CHECK(IsJSGlobalProxy());
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, JSGlobalProxy::kNativeContextOffset);
|
|
CHECK(map()->is_access_check_needed());
|
|
// Make sure that this object has no properties, elements.
|
|
CHECK_EQ(0, FixedArray::cast(elements())->length());
|
|
}
|
|
|
|
void JSGlobalObject::JSGlobalObjectVerify(Isolate* isolate) {
|
|
CHECK(IsJSGlobalObject());
|
|
// Do not check the dummy global object for the builtins.
|
|
if (global_dictionary()->NumberOfElements() == 0 &&
|
|
elements()->length() == 0) {
|
|
return;
|
|
}
|
|
JSObjectVerify(isolate);
|
|
}
|
|
|
|
void Oddball::OddballVerify(Isolate* isolate) {
|
|
CHECK(IsOddball());
|
|
Heap* heap = isolate->heap();
|
|
VerifyHeapPointer(isolate, to_string());
|
|
Object* number = to_number();
|
|
if (number->IsHeapObject()) {
|
|
CHECK(number == ReadOnlyRoots(heap).nan_value() ||
|
|
number == ReadOnlyRoots(heap).hole_nan_value());
|
|
} else {
|
|
CHECK(number->IsSmi());
|
|
int value = Smi::ToInt(number);
|
|
// Hidden oddballs have negative smis.
|
|
const int kLeastHiddenOddballNumber = -7;
|
|
CHECK_LE(value, 1);
|
|
CHECK_GE(value, kLeastHiddenOddballNumber);
|
|
}
|
|
|
|
ReadOnlyRoots roots(heap);
|
|
if (map() == roots.undefined_map()) {
|
|
CHECK(this == roots.undefined_value());
|
|
} else if (map() == roots.the_hole_map()) {
|
|
CHECK(this == roots.the_hole_value());
|
|
} else if (map() == roots.null_map()) {
|
|
CHECK(this == roots.null_value());
|
|
} else if (map() == roots.boolean_map()) {
|
|
CHECK(this == roots.true_value() || this == roots.false_value());
|
|
} else if (map() == roots.uninitialized_map()) {
|
|
CHECK(this == roots.uninitialized_value());
|
|
} else if (map() == roots.arguments_marker_map()) {
|
|
CHECK(this == roots.arguments_marker());
|
|
} else if (map() == roots.termination_exception_map()) {
|
|
CHECK(this == roots.termination_exception());
|
|
} else if (map() == roots.exception_map()) {
|
|
CHECK(this == roots.exception());
|
|
} else if (map() == roots.optimized_out_map()) {
|
|
CHECK(this == roots.optimized_out());
|
|
} else if (map() == roots.stale_register_map()) {
|
|
CHECK(this == roots.stale_register());
|
|
} else if (map() == roots.self_reference_marker_map()) {
|
|
// Multiple instances of this oddball may exist at once.
|
|
CHECK_EQ(kind(), Oddball::kSelfReferenceMarker);
|
|
} else {
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
void Cell::CellVerify(Isolate* isolate) {
|
|
CHECK(IsCell());
|
|
VerifyObjectField(isolate, kValueOffset);
|
|
}
|
|
|
|
void PropertyCell::PropertyCellVerify(Isolate* isolate) {
|
|
CHECK(IsPropertyCell());
|
|
VerifyObjectField(isolate, kValueOffset);
|
|
}
|
|
|
|
void CodeDataContainer::CodeDataContainerVerify(Isolate* isolate) {
|
|
CHECK(IsCodeDataContainer());
|
|
VerifyObjectField(isolate, kNextCodeLinkOffset);
|
|
CHECK(next_code_link()->IsCode() || next_code_link()->IsUndefined(isolate));
|
|
}
|
|
|
|
void Code::CodeVerify(Isolate* isolate) {
|
|
CHECK_LE(constant_pool_offset(), InstructionSize());
|
|
CHECK(IsAligned(raw_instruction_start(), kCodeAlignment));
|
|
relocation_info()->ObjectVerify(isolate);
|
|
CHECK(Code::SizeFor(body_size()) <= kMaxRegularHeapObjectSize ||
|
|
isolate->heap()->InSpace(*this, CODE_LO_SPACE));
|
|
Address last_gc_pc = kNullAddress;
|
|
|
|
for (RelocIterator it(*this); !it.done(); it.next()) {
|
|
it.rinfo()->Verify(isolate);
|
|
// 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(Isolate* isolate) {
|
|
JSObjectVerify(isolate);
|
|
CHECK(length()->IsNumber() || length()->IsUndefined(isolate));
|
|
// If a GC was caused while constructing this array, the elements
|
|
// pointer may point to a one pointer filler map.
|
|
if (!ElementsAreSafeToExamine()) return;
|
|
if (elements()->IsUndefined(isolate)) return;
|
|
CHECK(elements()->IsFixedArray() || elements()->IsFixedDoubleArray());
|
|
if (elements()->length() == 0) {
|
|
CHECK_EQ(elements(), ReadOnlyRoots(isolate).empty_fixed_array());
|
|
}
|
|
if (!length()->IsNumber()) return;
|
|
// Verify that the length and the elements backing store are in sync.
|
|
if (length()->IsSmi() && HasFastElements()) {
|
|
if (elements()->length() > 0) {
|
|
CHECK_IMPLIES(HasDoubleElements(), elements()->IsFixedDoubleArray());
|
|
}
|
|
int size = Smi::ToInt(length());
|
|
// Holey / Packed backing stores might have slack or might have not been
|
|
// properly initialized yet.
|
|
CHECK(size <= elements()->length() ||
|
|
elements() == ReadOnlyRoots(isolate).empty_fixed_array());
|
|
} else {
|
|
CHECK(HasDictionaryElements());
|
|
uint32_t array_length;
|
|
CHECK(length()->ToArrayLength(&array_length));
|
|
if (array_length == 0xFFFFFFFF) {
|
|
CHECK(length()->ToArrayLength(&array_length));
|
|
}
|
|
if (array_length != 0) {
|
|
NumberDictionary dict = NumberDictionary::cast(elements());
|
|
// The dictionary can never have more elements than the array length + 1.
|
|
// If the backing store grows the verification might be triggered with
|
|
// the old length in place.
|
|
uint32_t nof_elements = static_cast<uint32_t>(dict->NumberOfElements());
|
|
if (nof_elements != 0) nof_elements--;
|
|
CHECK_LE(nof_elements, array_length);
|
|
}
|
|
}
|
|
}
|
|
|
|
void JSSet::JSSetVerify(Isolate* isolate) {
|
|
CHECK(IsJSSet());
|
|
JSObjectVerify(isolate);
|
|
VerifyHeapPointer(isolate, table());
|
|
CHECK(table()->IsOrderedHashSet() || table()->IsUndefined(isolate));
|
|
// TODO(arv): Verify OrderedHashTable too.
|
|
}
|
|
|
|
void JSMap::JSMapVerify(Isolate* isolate) {
|
|
CHECK(IsJSMap());
|
|
JSObjectVerify(isolate);
|
|
VerifyHeapPointer(isolate, table());
|
|
CHECK(table()->IsOrderedHashMap() || table()->IsUndefined(isolate));
|
|
// TODO(arv): Verify OrderedHashTable too.
|
|
}
|
|
|
|
void JSSetIterator::JSSetIteratorVerify(Isolate* isolate) {
|
|
CHECK(IsJSSetIterator());
|
|
JSObjectVerify(isolate);
|
|
VerifyHeapPointer(isolate, table());
|
|
CHECK(table()->IsOrderedHashSet());
|
|
CHECK(index()->IsSmi());
|
|
}
|
|
|
|
void JSMapIterator::JSMapIteratorVerify(Isolate* isolate) {
|
|
CHECK(IsJSMapIterator());
|
|
JSObjectVerify(isolate);
|
|
VerifyHeapPointer(isolate, table());
|
|
CHECK(table()->IsOrderedHashMap());
|
|
CHECK(index()->IsSmi());
|
|
}
|
|
|
|
void JSWeakCell::JSWeakCellVerify(Isolate* isolate) {
|
|
CHECK(IsJSWeakCell());
|
|
JSObjectVerify(isolate);
|
|
|
|
CHECK(next()->IsJSWeakCell() || next()->IsUndefined(isolate));
|
|
if (next()->IsJSWeakCell()) {
|
|
CHECK_EQ(JSWeakCell::cast(next())->prev(), *this);
|
|
}
|
|
CHECK(prev()->IsJSWeakCell() || prev()->IsUndefined(isolate));
|
|
if (prev()->IsJSWeakCell()) {
|
|
CHECK_EQ(JSWeakCell::cast(prev())->next(), *this);
|
|
}
|
|
|
|
CHECK(factory()->IsUndefined(isolate) || factory()->IsJSWeakFactory());
|
|
}
|
|
|
|
void JSWeakFactory::JSWeakFactoryVerify(Isolate* isolate) {
|
|
CHECK(IsJSWeakFactory());
|
|
JSObjectVerify(isolate);
|
|
VerifyHeapPointer(isolate, cleanup());
|
|
CHECK(active_cells()->IsUndefined(isolate) || active_cells()->IsJSWeakCell());
|
|
if (active_cells()->IsJSWeakCell()) {
|
|
CHECK(JSWeakCell::cast(active_cells())->prev()->IsUndefined(isolate));
|
|
}
|
|
CHECK(cleared_cells()->IsUndefined(isolate) ||
|
|
cleared_cells()->IsJSWeakCell());
|
|
if (cleared_cells()->IsJSWeakCell()) {
|
|
CHECK(JSWeakCell::cast(cleared_cells())->prev()->IsUndefined(isolate));
|
|
}
|
|
}
|
|
|
|
void JSWeakFactoryCleanupIterator::JSWeakFactoryCleanupIteratorVerify(
|
|
Isolate* isolate) {
|
|
CHECK(IsJSWeakFactoryCleanupIterator());
|
|
JSObjectVerify(isolate);
|
|
VerifyHeapPointer(isolate, factory());
|
|
}
|
|
|
|
void WeakFactoryCleanupJobTask::WeakFactoryCleanupJobTaskVerify(
|
|
Isolate* isolate) {
|
|
CHECK(IsWeakFactoryCleanupJobTask());
|
|
CHECK(factory()->IsJSWeakFactory());
|
|
}
|
|
|
|
void JSWeakMap::JSWeakMapVerify(Isolate* isolate) {
|
|
CHECK(IsJSWeakMap());
|
|
JSObjectVerify(isolate);
|
|
VerifyHeapPointer(isolate, table());
|
|
CHECK(table()->IsEphemeronHashTable() || table()->IsUndefined(isolate));
|
|
}
|
|
|
|
void JSArrayIterator::JSArrayIteratorVerify(Isolate* isolate) {
|
|
CHECK(IsJSArrayIterator());
|
|
JSObjectVerify(isolate);
|
|
CHECK(iterated_object()->IsJSReceiver());
|
|
|
|
CHECK_GE(next_index()->Number(), 0);
|
|
CHECK_LE(next_index()->Number(), kMaxSafeInteger);
|
|
|
|
if (iterated_object()->IsJSTypedArray()) {
|
|
// JSTypedArray::length is limited to Smi range.
|
|
CHECK(next_index()->IsSmi());
|
|
CHECK_LE(next_index()->Number(), Smi::kMaxValue);
|
|
} else if (iterated_object()->IsJSArray()) {
|
|
// JSArray::length is limited to Uint32 range.
|
|
CHECK_LE(next_index()->Number(), kMaxUInt32);
|
|
}
|
|
}
|
|
|
|
void JSStringIterator::JSStringIteratorVerify(Isolate* isolate) {
|
|
CHECK(IsJSStringIterator());
|
|
JSObjectVerify(isolate);
|
|
CHECK(string()->IsString());
|
|
|
|
CHECK_GE(index(), 0);
|
|
CHECK_LE(index(), String::kMaxLength);
|
|
}
|
|
|
|
void JSAsyncFromSyncIterator::JSAsyncFromSyncIteratorVerify(Isolate* isolate) {
|
|
CHECK(IsJSAsyncFromSyncIterator());
|
|
JSObjectVerify(isolate);
|
|
VerifyHeapPointer(isolate, sync_iterator());
|
|
}
|
|
|
|
void JSWeakSet::JSWeakSetVerify(Isolate* isolate) {
|
|
CHECK(IsJSWeakSet());
|
|
JSObjectVerify(isolate);
|
|
VerifyHeapPointer(isolate, table());
|
|
CHECK(table()->IsEphemeronHashTable() || table()->IsUndefined(isolate));
|
|
}
|
|
|
|
void Microtask::MicrotaskVerify(Isolate* isolate) { CHECK(IsMicrotask()); }
|
|
|
|
void CallableTask::CallableTaskVerify(Isolate* isolate) {
|
|
CHECK(IsCallableTask());
|
|
MicrotaskVerify(isolate);
|
|
VerifyHeapPointer(isolate, callable());
|
|
CHECK(callable()->IsCallable());
|
|
VerifyHeapPointer(isolate, context());
|
|
CHECK(context()->IsContext());
|
|
}
|
|
|
|
void CallbackTask::CallbackTaskVerify(Isolate* isolate) {
|
|
CHECK(IsCallbackTask());
|
|
MicrotaskVerify(isolate);
|
|
VerifyHeapPointer(isolate, callback());
|
|
VerifyHeapPointer(isolate, data());
|
|
}
|
|
|
|
void PromiseReactionJobTask::PromiseReactionJobTaskVerify(Isolate* isolate) {
|
|
CHECK(IsPromiseReactionJobTask());
|
|
MicrotaskVerify(isolate);
|
|
VerifyPointer(isolate, argument());
|
|
VerifyHeapPointer(isolate, context());
|
|
CHECK(context()->IsContext());
|
|
VerifyHeapPointer(isolate, handler());
|
|
CHECK(handler()->IsUndefined(isolate) || handler()->IsCallable());
|
|
VerifyHeapPointer(isolate, promise_or_capability());
|
|
CHECK(promise_or_capability()->IsJSPromise() ||
|
|
promise_or_capability()->IsPromiseCapability() ||
|
|
promise_or_capability()->IsUndefined(isolate));
|
|
}
|
|
|
|
void PromiseFulfillReactionJobTask::PromiseFulfillReactionJobTaskVerify(
|
|
Isolate* isolate) {
|
|
CHECK(IsPromiseFulfillReactionJobTask());
|
|
PromiseReactionJobTaskVerify(isolate);
|
|
}
|
|
|
|
void PromiseRejectReactionJobTask::PromiseRejectReactionJobTaskVerify(
|
|
Isolate* isolate) {
|
|
CHECK(IsPromiseRejectReactionJobTask());
|
|
PromiseReactionJobTaskVerify(isolate);
|
|
}
|
|
|
|
void PromiseResolveThenableJobTask::PromiseResolveThenableJobTaskVerify(
|
|
Isolate* isolate) {
|
|
CHECK(IsPromiseResolveThenableJobTask());
|
|
MicrotaskVerify(isolate);
|
|
VerifyHeapPointer(isolate, context());
|
|
CHECK(context()->IsContext());
|
|
VerifyHeapPointer(isolate, promise_to_resolve());
|
|
CHECK(promise_to_resolve()->IsJSPromise());
|
|
VerifyHeapPointer(isolate, then());
|
|
CHECK(then()->IsCallable());
|
|
CHECK(then()->IsJSReceiver());
|
|
VerifyHeapPointer(isolate, thenable());
|
|
CHECK(thenable()->IsJSReceiver());
|
|
}
|
|
|
|
void PromiseCapability::PromiseCapabilityVerify(Isolate* isolate) {
|
|
CHECK(IsPromiseCapability());
|
|
|
|
VerifyHeapPointer(isolate, promise());
|
|
CHECK(promise()->IsJSReceiver() || promise()->IsUndefined(isolate));
|
|
VerifyPointer(isolate, resolve());
|
|
VerifyPointer(isolate, reject());
|
|
}
|
|
|
|
void PromiseReaction::PromiseReactionVerify(Isolate* isolate) {
|
|
CHECK(IsPromiseReaction());
|
|
|
|
VerifyPointer(isolate, next());
|
|
CHECK(next()->IsSmi() || next()->IsPromiseReaction());
|
|
VerifyHeapPointer(isolate, reject_handler());
|
|
CHECK(reject_handler()->IsUndefined(isolate) ||
|
|
reject_handler()->IsCallable());
|
|
VerifyHeapPointer(isolate, fulfill_handler());
|
|
CHECK(fulfill_handler()->IsUndefined(isolate) ||
|
|
fulfill_handler()->IsCallable());
|
|
VerifyHeapPointer(isolate, promise_or_capability());
|
|
CHECK(promise_or_capability()->IsJSPromise() ||
|
|
promise_or_capability()->IsPromiseCapability() ||
|
|
promise_or_capability()->IsUndefined(isolate));
|
|
}
|
|
|
|
void JSPromise::JSPromiseVerify(Isolate* isolate) {
|
|
CHECK(IsJSPromise());
|
|
JSObjectVerify(isolate);
|
|
VerifyPointer(isolate, reactions_or_result());
|
|
VerifySmiField(kFlagsOffset);
|
|
if (status() == Promise::kPending) {
|
|
CHECK(reactions()->IsSmi() || reactions()->IsPromiseReaction());
|
|
}
|
|
}
|
|
|
|
template <typename Derived>
|
|
void SmallOrderedHashTable<Derived>::SmallOrderedHashTableVerify(
|
|
Isolate* isolate) {
|
|
CHECK(IsSmallOrderedHashTable());
|
|
|
|
int capacity = Capacity();
|
|
CHECK_GE(capacity, kMinCapacity);
|
|
CHECK_LE(capacity, kMaxCapacity);
|
|
|
|
for (int entry = 0; entry < NumberOfBuckets(); entry++) {
|
|
int bucket = GetFirstEntry(entry);
|
|
if (bucket == kNotFound) continue;
|
|
CHECK_GE(bucket, 0);
|
|
CHECK_LE(bucket, capacity);
|
|
}
|
|
|
|
for (int entry = 0; entry < NumberOfElements(); entry++) {
|
|
int chain = GetNextEntry(entry);
|
|
if (chain == kNotFound) continue;
|
|
CHECK_GE(chain, 0);
|
|
CHECK_LE(chain, capacity);
|
|
}
|
|
|
|
for (int entry = 0; entry < NumberOfElements(); entry++) {
|
|
for (int offset = 0; offset < Derived::kEntrySize; offset++) {
|
|
Object* val = GetDataEntry(entry, offset);
|
|
VerifyPointer(isolate, val);
|
|
}
|
|
}
|
|
|
|
for (int entry = NumberOfElements(); entry < NumberOfDeletedElements();
|
|
entry++) {
|
|
for (int offset = 0; offset < Derived::kEntrySize; offset++) {
|
|
Object* val = GetDataEntry(entry, offset);
|
|
CHECK(val->IsTheHole(isolate));
|
|
}
|
|
}
|
|
|
|
for (int entry = NumberOfElements() + NumberOfDeletedElements();
|
|
entry < Capacity(); entry++) {
|
|
for (int offset = 0; offset < Derived::kEntrySize; offset++) {
|
|
Object* val = GetDataEntry(entry, offset);
|
|
CHECK(val->IsTheHole(isolate));
|
|
}
|
|
}
|
|
}
|
|
|
|
template void SmallOrderedHashTable<
|
|
SmallOrderedHashMap>::SmallOrderedHashTableVerify(Isolate* isolate);
|
|
template void SmallOrderedHashTable<
|
|
SmallOrderedHashSet>::SmallOrderedHashTableVerify(Isolate* isolate);
|
|
template void SmallOrderedHashTable<
|
|
SmallOrderedNameDictionary>::SmallOrderedHashTableVerify(Isolate* isolate);
|
|
|
|
void JSRegExp::JSRegExpVerify(Isolate* isolate) {
|
|
JSObjectVerify(isolate);
|
|
CHECK(data()->IsUndefined(isolate) || data()->IsFixedArray());
|
|
switch (TypeTag()) {
|
|
case JSRegExp::ATOM: {
|
|
FixedArray arr = FixedArray::cast(data());
|
|
CHECK(arr->get(JSRegExp::kAtomPatternIndex)->IsString());
|
|
break;
|
|
}
|
|
case JSRegExp::IRREGEXP: {
|
|
bool is_native = RegExpImpl::UsesNativeRegExp();
|
|
|
|
FixedArray arr = FixedArray::cast(data());
|
|
Object* one_byte_data = arr->get(JSRegExp::kIrregexpLatin1CodeIndex);
|
|
// Smi : Not compiled yet (-1).
|
|
// Code/ByteArray: Compiled code.
|
|
CHECK(
|
|
(one_byte_data->IsSmi() &&
|
|
Smi::ToInt(one_byte_data) == JSRegExp::kUninitializedValue) ||
|
|
(is_native ? one_byte_data->IsCode() : one_byte_data->IsByteArray()));
|
|
Object* uc16_data = arr->get(JSRegExp::kIrregexpUC16CodeIndex);
|
|
CHECK((uc16_data->IsSmi() &&
|
|
Smi::ToInt(uc16_data) == JSRegExp::kUninitializedValue) ||
|
|
(is_native ? uc16_data->IsCode() : uc16_data->IsByteArray()));
|
|
|
|
CHECK(arr->get(JSRegExp::kIrregexpCaptureCountIndex)->IsSmi());
|
|
CHECK(arr->get(JSRegExp::kIrregexpMaxRegisterCountIndex)->IsSmi());
|
|
break;
|
|
}
|
|
default:
|
|
CHECK_EQ(JSRegExp::NOT_COMPILED, TypeTag());
|
|
CHECK(data()->IsUndefined(isolate));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void JSRegExpStringIterator::JSRegExpStringIteratorVerify(Isolate* isolate) {
|
|
CHECK(IsJSRegExpStringIterator());
|
|
JSObjectVerify(isolate);
|
|
CHECK(iterating_string()->IsString());
|
|
CHECK(iterating_regexp()->IsObject());
|
|
VerifySmiField(kFlagsOffset);
|
|
}
|
|
|
|
void JSProxy::JSProxyVerify(Isolate* isolate) {
|
|
CHECK(IsJSProxy());
|
|
CHECK(map()->GetConstructor()->IsJSFunction());
|
|
VerifyPointer(isolate, target());
|
|
VerifyPointer(isolate, handler());
|
|
if (!IsRevoked()) {
|
|
CHECK_EQ(target()->IsCallable(), map()->is_callable());
|
|
CHECK_EQ(target()->IsConstructor(), map()->is_constructor());
|
|
}
|
|
CHECK(map()->prototype()->IsNull(isolate));
|
|
// There should be no properties on a Proxy.
|
|
CHECK_EQ(0, map()->NumberOfOwnDescriptors());
|
|
}
|
|
|
|
void JSArrayBuffer::JSArrayBufferVerify(Isolate* isolate) {
|
|
CHECK(IsJSArrayBuffer());
|
|
if (FIELD_SIZE(kOptionalPaddingOffset)) {
|
|
CHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset));
|
|
CHECK_EQ(0,
|
|
*reinterpret_cast<uint32_t*>(address() + kOptionalPaddingOffset));
|
|
}
|
|
JSObjectVerify(isolate);
|
|
}
|
|
|
|
void JSArrayBufferView::JSArrayBufferViewVerify(Isolate* isolate) {
|
|
CHECK(IsJSArrayBufferView());
|
|
JSObjectVerify(isolate);
|
|
VerifyPointer(isolate, buffer());
|
|
CHECK(buffer()->IsJSArrayBuffer() || buffer()->IsUndefined(isolate) ||
|
|
buffer() == Smi::kZero);
|
|
CHECK_LE(byte_length(), JSArrayBuffer::kMaxByteLength);
|
|
CHECK_LE(byte_offset(), JSArrayBuffer::kMaxByteLength);
|
|
}
|
|
|
|
void JSTypedArray::JSTypedArrayVerify(Isolate* isolate) {
|
|
CHECK(IsJSTypedArray());
|
|
JSArrayBufferViewVerify(isolate);
|
|
VerifyPointer(isolate, raw_length());
|
|
CHECK(raw_length()->IsSmi() || raw_length()->IsUndefined(isolate));
|
|
VerifyPointer(isolate, elements());
|
|
}
|
|
|
|
void JSDataView::JSDataViewVerify(Isolate* isolate) {
|
|
CHECK(IsJSDataView());
|
|
JSArrayBufferViewVerify(isolate);
|
|
}
|
|
|
|
void Foreign::ForeignVerify(Isolate* isolate) { CHECK(IsForeign()); }
|
|
|
|
void AsyncGeneratorRequest::AsyncGeneratorRequestVerify(Isolate* isolate) {
|
|
CHECK(IsAsyncGeneratorRequest());
|
|
VerifySmiField(kResumeModeOffset);
|
|
CHECK_GE(resume_mode(), JSGeneratorObject::kNext);
|
|
CHECK_LE(resume_mode(), JSGeneratorObject::kThrow);
|
|
CHECK(promise()->IsJSPromise());
|
|
VerifyPointer(isolate, value());
|
|
VerifyPointer(isolate, next());
|
|
next()->ObjectVerify(isolate);
|
|
}
|
|
|
|
void BigInt::BigIntVerify(Isolate* isolate) {
|
|
CHECK(IsBigInt());
|
|
CHECK_GE(length(), 0);
|
|
CHECK_IMPLIES(is_zero(), !sign()); // There is no -0n.
|
|
}
|
|
|
|
void JSModuleNamespace::JSModuleNamespaceVerify(Isolate* isolate) {
|
|
CHECK(IsJSModuleNamespace());
|
|
VerifyPointer(isolate, module());
|
|
}
|
|
|
|
void ModuleInfoEntry::ModuleInfoEntryVerify(Isolate* isolate) {
|
|
CHECK(IsModuleInfoEntry());
|
|
|
|
CHECK(export_name()->IsUndefined(isolate) || export_name()->IsString());
|
|
CHECK(local_name()->IsUndefined(isolate) || local_name()->IsString());
|
|
CHECK(import_name()->IsUndefined(isolate) || import_name()->IsString());
|
|
|
|
VerifySmiField(kModuleRequestOffset);
|
|
VerifySmiField(kCellIndexOffset);
|
|
VerifySmiField(kBegPosOffset);
|
|
VerifySmiField(kEndPosOffset);
|
|
|
|
CHECK_IMPLIES(import_name()->IsString(), module_request() >= 0);
|
|
CHECK_IMPLIES(export_name()->IsString() && import_name()->IsString(),
|
|
local_name()->IsUndefined(isolate));
|
|
}
|
|
|
|
void Module::ModuleVerify(Isolate* isolate) {
|
|
CHECK(IsModule());
|
|
|
|
VerifyPointer(isolate, code());
|
|
VerifyPointer(isolate, exports());
|
|
VerifyPointer(isolate, module_namespace());
|
|
VerifyPointer(isolate, requested_modules());
|
|
VerifyPointer(isolate, script());
|
|
VerifyPointer(isolate, import_meta());
|
|
VerifyPointer(isolate, exception());
|
|
VerifySmiField(kHashOffset);
|
|
VerifySmiField(kStatusOffset);
|
|
|
|
CHECK((status() >= kEvaluating && code()->IsModuleInfo()) ||
|
|
(status() == kInstantiated && code()->IsJSGeneratorObject()) ||
|
|
(status() == kInstantiating && code()->IsJSFunction()) ||
|
|
(code()->IsSharedFunctionInfo()));
|
|
|
|
CHECK_EQ(status() == kErrored, !exception()->IsTheHole(isolate));
|
|
|
|
CHECK(module_namespace()->IsUndefined(isolate) ||
|
|
module_namespace()->IsJSModuleNamespace());
|
|
if (module_namespace()->IsJSModuleNamespace()) {
|
|
CHECK_LE(kInstantiating, status());
|
|
CHECK_EQ(JSModuleNamespace::cast(module_namespace())->module(), this);
|
|
}
|
|
|
|
CHECK_EQ(requested_modules()->length(), info()->module_requests()->length());
|
|
|
|
CHECK(import_meta()->IsTheHole(isolate) || import_meta()->IsJSObject());
|
|
|
|
CHECK_NE(hash(), 0);
|
|
}
|
|
|
|
void PrototypeInfo::PrototypeInfoVerify(Isolate* isolate) {
|
|
CHECK(IsPrototypeInfo());
|
|
Object* module_ns = module_namespace();
|
|
CHECK(module_ns->IsJSModuleNamespace() || module_ns->IsUndefined(isolate));
|
|
if (prototype_users()->IsWeakArrayList()) {
|
|
PrototypeUsers::Verify(WeakArrayList::cast(prototype_users()));
|
|
} else {
|
|
CHECK(prototype_users()->IsSmi());
|
|
}
|
|
}
|
|
|
|
void PrototypeUsers::Verify(WeakArrayList array) {
|
|
if (array->length() == 0) {
|
|
// Allow empty & uninitialized lists.
|
|
return;
|
|
}
|
|
// Verify empty slot chain.
|
|
int empty_slot = Smi::ToInt(empty_slot_index(array));
|
|
int empty_slots_count = 0;
|
|
while (empty_slot != kNoEmptySlotsMarker) {
|
|
CHECK_GT(empty_slot, 0);
|
|
CHECK_LT(empty_slot, array->length());
|
|
empty_slot = array->Get(empty_slot).ToSmi().value();
|
|
++empty_slots_count;
|
|
}
|
|
|
|
// Verify that all elements are either weak pointers or SMIs marking empty
|
|
// slots.
|
|
int weak_maps_count = 0;
|
|
for (int i = kFirstIndex; i < array->length(); ++i) {
|
|
HeapObject* heap_object;
|
|
MaybeObject object = array->Get(i);
|
|
if ((object->GetHeapObjectIfWeak(&heap_object) && heap_object->IsMap()) ||
|
|
object->IsCleared()) {
|
|
++weak_maps_count;
|
|
} else {
|
|
CHECK(object->IsSmi());
|
|
}
|
|
}
|
|
|
|
CHECK_EQ(weak_maps_count + empty_slots_count + 1, array->length());
|
|
}
|
|
|
|
void Tuple2::Tuple2Verify(Isolate* isolate) {
|
|
CHECK(IsTuple2());
|
|
Heap* heap = isolate->heap();
|
|
if (this == ReadOnlyRoots(heap).empty_enum_cache()) {
|
|
CHECK_EQ(ReadOnlyRoots(heap).empty_fixed_array(),
|
|
EnumCache::cast(this)->keys());
|
|
CHECK_EQ(ReadOnlyRoots(heap).empty_fixed_array(),
|
|
EnumCache::cast(this)->indices());
|
|
} else {
|
|
VerifyObjectField(isolate, kValue1Offset);
|
|
VerifyObjectField(isolate, kValue2Offset);
|
|
}
|
|
}
|
|
|
|
void Tuple3::Tuple3Verify(Isolate* isolate) {
|
|
CHECK(IsTuple3());
|
|
VerifyObjectField(isolate, kValue1Offset);
|
|
VerifyObjectField(isolate, kValue2Offset);
|
|
VerifyObjectField(isolate, kValue3Offset);
|
|
}
|
|
|
|
void ObjectBoilerplateDescription::ObjectBoilerplateDescriptionVerify(
|
|
Isolate* isolate) {
|
|
CHECK(IsObjectBoilerplateDescription());
|
|
CHECK_GE(this->length(),
|
|
ObjectBoilerplateDescription::kDescriptionStartIndex);
|
|
this->FixedArrayVerify(isolate);
|
|
}
|
|
|
|
void ArrayBoilerplateDescription::ArrayBoilerplateDescriptionVerify(
|
|
Isolate* isolate) {
|
|
CHECK(IsArrayBoilerplateDescription());
|
|
CHECK(constant_elements()->IsFixedArrayBase());
|
|
VerifyObjectField(isolate, kConstantElementsOffset);
|
|
}
|
|
|
|
void AsmWasmData::AsmWasmDataVerify(Isolate* isolate) {
|
|
CHECK(IsAsmWasmData());
|
|
VerifyObjectField(isolate, kManagedNativeModuleOffset);
|
|
VerifyObjectField(isolate, kExportWrappersOffset);
|
|
VerifyObjectField(isolate, kAsmJsOffsetTableOffset);
|
|
CHECK(uses_bitset()->IsHeapNumber());
|
|
VerifyObjectField(isolate, kUsesBitsetOffset);
|
|
}
|
|
|
|
void WasmDebugInfo::WasmDebugInfoVerify(Isolate* isolate) {
|
|
CHECK(IsWasmDebugInfo());
|
|
VerifyObjectField(isolate, kInstanceOffset);
|
|
CHECK(wasm_instance()->IsWasmInstanceObject());
|
|
VerifyObjectField(isolate, kInterpreterHandleOffset);
|
|
CHECK(interpreter_handle()->IsUndefined(isolate) ||
|
|
interpreter_handle()->IsForeign());
|
|
VerifyObjectField(isolate, kInterpretedFunctionsOffset);
|
|
VerifyObjectField(isolate, kLocalsNamesOffset);
|
|
VerifyObjectField(isolate, kCWasmEntriesOffset);
|
|
VerifyObjectField(isolate, kCWasmEntryMapOffset);
|
|
}
|
|
|
|
void WasmExceptionTag::WasmExceptionTagVerify(Isolate* isolate) {
|
|
CHECK(IsWasmExceptionTag());
|
|
VerifySmiField(kIndexOffset);
|
|
}
|
|
|
|
void WasmInstanceObject::WasmInstanceObjectVerify(Isolate* isolate) {
|
|
JSObjectVerify(isolate);
|
|
CHECK(IsWasmInstanceObject());
|
|
|
|
// Just generically check all tagged fields. Don't check the untagged fields,
|
|
// as some of them might still contain the "undefined" value if the
|
|
// WasmInstanceObject is not fully set up yet.
|
|
for (int offset = kHeaderSize; offset < kFirstUntaggedOffset;
|
|
offset += kPointerSize) {
|
|
VerifyObjectField(isolate, offset);
|
|
}
|
|
}
|
|
|
|
void WasmExportedFunctionData::WasmExportedFunctionDataVerify(
|
|
Isolate* isolate) {
|
|
CHECK(IsWasmExportedFunctionData());
|
|
VerifyObjectField(isolate, kWrapperCodeOffset);
|
|
CHECK(wrapper_code()->kind() == Code::JS_TO_WASM_FUNCTION ||
|
|
wrapper_code()->kind() == Code::C_WASM_ENTRY);
|
|
VerifyObjectField(isolate, kInstanceOffset);
|
|
VerifySmiField(kJumpTableOffsetOffset);
|
|
VerifySmiField(kFunctionIndexOffset);
|
|
}
|
|
|
|
void WasmModuleObject::WasmModuleObjectVerify(Isolate* isolate) {
|
|
CHECK(IsWasmModuleObject());
|
|
VerifyObjectField(isolate, kNativeModuleOffset);
|
|
CHECK(managed_native_module()->IsForeign());
|
|
VerifyObjectField(isolate, kExportWrappersOffset);
|
|
CHECK(export_wrappers()->IsFixedArray());
|
|
VerifyObjectField(isolate, kScriptOffset);
|
|
VerifyObjectField(isolate, kAsmJsOffsetTableOffset);
|
|
VerifyObjectField(isolate, kBreakPointInfosOffset);
|
|
}
|
|
|
|
void DataHandler::DataHandlerVerify(Isolate* isolate) {
|
|
CHECK(IsDataHandler());
|
|
CHECK_IMPLIES(!smi_handler()->IsSmi(),
|
|
smi_handler()->IsCode() && IsStoreHandler());
|
|
CHECK(validity_cell()->IsSmi() || validity_cell()->IsCell());
|
|
int data_count = data_field_count();
|
|
if (data_count >= 1) {
|
|
VerifyMaybeObjectField(isolate, kData1Offset);
|
|
}
|
|
if (data_count >= 2) {
|
|
VerifyMaybeObjectField(isolate, kData2Offset);
|
|
}
|
|
if (data_count >= 3) {
|
|
VerifyMaybeObjectField(isolate, kData3Offset);
|
|
}
|
|
}
|
|
|
|
void LoadHandler::LoadHandlerVerify(Isolate* isolate) {
|
|
DataHandler::DataHandlerVerify(isolate);
|
|
// TODO(ishell): check handler integrity
|
|
}
|
|
|
|
void StoreHandler::StoreHandlerVerify(Isolate* isolate) {
|
|
DataHandler::DataHandlerVerify(isolate);
|
|
// TODO(ishell): check handler integrity
|
|
}
|
|
|
|
void AccessorInfo::AccessorInfoVerify(Isolate* isolate) {
|
|
CHECK(IsAccessorInfo());
|
|
VerifyPointer(isolate, name());
|
|
VerifyPointer(isolate, expected_receiver_type());
|
|
VerifyForeignPointer(isolate, this, getter());
|
|
VerifyForeignPointer(isolate, this, setter());
|
|
VerifyForeignPointer(isolate, this, js_getter());
|
|
VerifyPointer(isolate, data());
|
|
}
|
|
|
|
void AccessorPair::AccessorPairVerify(Isolate* isolate) {
|
|
CHECK(IsAccessorPair());
|
|
VerifyPointer(isolate, getter());
|
|
VerifyPointer(isolate, setter());
|
|
}
|
|
|
|
void AccessCheckInfo::AccessCheckInfoVerify(Isolate* isolate) {
|
|
CHECK(IsAccessCheckInfo());
|
|
VerifyPointer(isolate, callback());
|
|
VerifyPointer(isolate, named_interceptor());
|
|
VerifyPointer(isolate, indexed_interceptor());
|
|
VerifyPointer(isolate, data());
|
|
}
|
|
|
|
void CallHandlerInfo::CallHandlerInfoVerify(Isolate* isolate) {
|
|
CHECK(IsCallHandlerInfo());
|
|
CHECK(map() == ReadOnlyRoots(isolate).side_effect_call_handler_info_map() ||
|
|
map() ==
|
|
ReadOnlyRoots(isolate).side_effect_free_call_handler_info_map() ||
|
|
map() == ReadOnlyRoots(isolate)
|
|
.next_call_side_effect_free_call_handler_info_map());
|
|
VerifyPointer(isolate, callback());
|
|
VerifyPointer(isolate, js_callback());
|
|
VerifyPointer(isolate, data());
|
|
}
|
|
|
|
void InterceptorInfo::InterceptorInfoVerify(Isolate* isolate) {
|
|
CHECK(IsInterceptorInfo());
|
|
VerifyForeignPointer(isolate, this, getter());
|
|
VerifyForeignPointer(isolate, this, setter());
|
|
VerifyForeignPointer(isolate, this, query());
|
|
VerifyForeignPointer(isolate, this, deleter());
|
|
VerifyForeignPointer(isolate, this, enumerator());
|
|
VerifyPointer(isolate, data());
|
|
VerifySmiField(kFlagsOffset);
|
|
}
|
|
|
|
void TemplateInfo::TemplateInfoVerify(Isolate* isolate) {
|
|
VerifyPointer(isolate, tag());
|
|
VerifyPointer(isolate, property_list());
|
|
VerifyPointer(isolate, property_accessors());
|
|
}
|
|
|
|
void FunctionTemplateInfo::FunctionTemplateInfoVerify(Isolate* isolate) {
|
|
CHECK(IsFunctionTemplateInfo());
|
|
TemplateInfoVerify(isolate);
|
|
VerifyPointer(isolate, serial_number());
|
|
VerifyPointer(isolate, call_code());
|
|
VerifyPointer(isolate, signature());
|
|
VerifyPointer(isolate, cached_property_name());
|
|
VerifyPointer(isolate, rare_data());
|
|
}
|
|
|
|
void FunctionTemplateRareData::FunctionTemplateRareDataVerify(
|
|
Isolate* isolate) {
|
|
CHECK(IsFunctionTemplateRareData());
|
|
VerifyPointer(isolate, prototype_template());
|
|
VerifyPointer(isolate, parent_template());
|
|
VerifyPointer(isolate, named_property_handler());
|
|
VerifyPointer(isolate, indexed_property_handler());
|
|
VerifyPointer(isolate, instance_template());
|
|
VerifyPointer(isolate, access_check_info());
|
|
}
|
|
|
|
void ObjectTemplateInfo::ObjectTemplateInfoVerify(Isolate* isolate) {
|
|
CHECK(IsObjectTemplateInfo());
|
|
TemplateInfoVerify(isolate);
|
|
VerifyPointer(isolate, constructor());
|
|
VerifyPointer(isolate, data());
|
|
}
|
|
|
|
void AllocationSite::AllocationSiteVerify(Isolate* isolate) {
|
|
CHECK(IsAllocationSite());
|
|
}
|
|
|
|
void AllocationMemento::AllocationMementoVerify(Isolate* isolate) {
|
|
CHECK(IsAllocationMemento());
|
|
VerifyHeapPointer(isolate, allocation_site());
|
|
CHECK(!IsValid() || GetAllocationSite()->IsAllocationSite());
|
|
}
|
|
|
|
void Script::ScriptVerify(Isolate* isolate) {
|
|
CHECK(IsScript());
|
|
VerifyPointer(isolate, source());
|
|
VerifyPointer(isolate, name());
|
|
VerifyPointer(isolate, line_ends());
|
|
for (int i = 0; i < shared_function_infos()->length(); ++i) {
|
|
MaybeObject maybe_object = shared_function_infos()->Get(i);
|
|
HeapObject* heap_object;
|
|
CHECK(maybe_object->IsWeak() || maybe_object->IsCleared() ||
|
|
(maybe_object->GetHeapObjectIfStrong(&heap_object) &&
|
|
heap_object->IsUndefined(isolate)));
|
|
}
|
|
}
|
|
|
|
void NormalizedMapCache::NormalizedMapCacheVerify(Isolate* isolate) {
|
|
WeakFixedArray::cast(*this)->WeakFixedArrayVerify(isolate);
|
|
if (FLAG_enable_slow_asserts) {
|
|
for (int i = 0; i < length(); i++) {
|
|
MaybeObject e = WeakFixedArray::Get(i);
|
|
HeapObject* heap_object;
|
|
if (e->GetHeapObjectIfWeak(&heap_object)) {
|
|
Map::cast(heap_object)->DictionaryMapVerify(isolate);
|
|
} else {
|
|
CHECK(e->IsCleared() || (e->GetHeapObjectIfStrong(&heap_object) &&
|
|
heap_object->IsUndefined(isolate)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebugInfo::DebugInfoVerify(Isolate* isolate) {
|
|
CHECK(IsDebugInfo());
|
|
VerifyPointer(isolate, shared());
|
|
VerifyPointer(isolate, script());
|
|
VerifyPointer(isolate, original_bytecode_array());
|
|
VerifyPointer(isolate, break_points());
|
|
}
|
|
|
|
void StackFrameInfo::StackFrameInfoVerify(Isolate* isolate) {
|
|
CHECK(IsStackFrameInfo());
|
|
VerifyPointer(isolate, script_name());
|
|
VerifyPointer(isolate, script_name_or_source_url());
|
|
VerifyPointer(isolate, function_name());
|
|
}
|
|
|
|
void PreParsedScopeData::PreParsedScopeDataVerify(Isolate* isolate) {
|
|
CHECK(IsPreParsedScopeData());
|
|
CHECK(scope_data()->IsByteArray());
|
|
CHECK_GE(length(), 0);
|
|
|
|
for (int i = 0; i < length(); ++i) {
|
|
Object* child = child_data(i);
|
|
CHECK(child->IsPreParsedScopeData() || child->IsNull());
|
|
VerifyPointer(isolate, child);
|
|
}
|
|
}
|
|
|
|
void UncompiledDataWithPreParsedScope::UncompiledDataWithPreParsedScopeVerify(
|
|
Isolate* isolate) {
|
|
CHECK(IsUncompiledDataWithPreParsedScope());
|
|
VerifyPointer(isolate, inferred_name());
|
|
VerifyPointer(isolate, pre_parsed_scope_data());
|
|
}
|
|
|
|
void UncompiledDataWithoutPreParsedScope::
|
|
UncompiledDataWithoutPreParsedScopeVerify(Isolate* isolate) {
|
|
CHECK(IsUncompiledDataWithoutPreParsedScope());
|
|
VerifyPointer(isolate, inferred_name());
|
|
}
|
|
|
|
void InterpreterData::InterpreterDataVerify(Isolate* isolate) {
|
|
CHECK(IsInterpreterData());
|
|
CHECK(bytecode_array()->IsBytecodeArray());
|
|
CHECK(interpreter_trampoline()->IsCode());
|
|
}
|
|
|
|
#ifdef V8_INTL_SUPPORT
|
|
void JSV8BreakIterator::JSV8BreakIteratorVerify(Isolate* isolate) {
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kLocaleOffset);
|
|
VerifyObjectField(isolate, kTypeOffset);
|
|
VerifyObjectField(isolate, kBreakIteratorOffset);
|
|
VerifyObjectField(isolate, kUnicodeStringOffset);
|
|
VerifyObjectField(isolate, kBoundAdoptTextOffset);
|
|
VerifyObjectField(isolate, kBoundFirstOffset);
|
|
VerifyObjectField(isolate, kBoundNextOffset);
|
|
VerifyObjectField(isolate, kBoundCurrentOffset);
|
|
VerifyObjectField(isolate, kBoundBreakTypeOffset);
|
|
}
|
|
|
|
void JSCollator::JSCollatorVerify(Isolate* isolate) {
|
|
CHECK(IsJSCollator());
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kICUCollatorOffset);
|
|
VerifyObjectField(isolate, kBoundCompareOffset);
|
|
}
|
|
|
|
void JSDateTimeFormat::JSDateTimeFormatVerify(Isolate* isolate) {
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kICULocaleOffset);
|
|
VerifyObjectField(isolate, kICUSimpleDateFormatOffset);
|
|
VerifyObjectField(isolate, kBoundFormatOffset);
|
|
}
|
|
|
|
void JSListFormat::JSListFormatVerify(Isolate* isolate) {
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kLocaleOffset);
|
|
VerifyObjectField(isolate, kICUFormatterOffset);
|
|
VerifyObjectField(isolate, kFlagsOffset);
|
|
}
|
|
|
|
void JSLocale::JSLocaleVerify(Isolate* isolate) {
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kLanguageOffset);
|
|
VerifyObjectField(isolate, kScriptOffset);
|
|
VerifyObjectField(isolate, kRegionOffset);
|
|
VerifyObjectField(isolate, kBaseNameOffset);
|
|
VerifyObjectField(isolate, kLocaleOffset);
|
|
// Unicode extension fields.
|
|
VerifyObjectField(isolate, kFlagsOffset);
|
|
VerifyObjectField(isolate, kCalendarOffset);
|
|
VerifyObjectField(isolate, kCollationOffset);
|
|
VerifyObjectField(isolate, kNumberingSystemOffset);
|
|
}
|
|
|
|
void JSNumberFormat::JSNumberFormatVerify(Isolate* isolate) {
|
|
CHECK(IsJSNumberFormat());
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kLocaleOffset);
|
|
VerifyObjectField(isolate, kICUNumberFormatOffset);
|
|
VerifyObjectField(isolate, kBoundFormatOffset);
|
|
VerifyObjectField(isolate, kFlagsOffset);
|
|
}
|
|
|
|
void JSPluralRules::JSPluralRulesVerify(Isolate* isolate) {
|
|
CHECK(IsJSPluralRules());
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kLocaleOffset);
|
|
VerifyObjectField(isolate, kFlagsOffset);
|
|
VerifyObjectField(isolate, kICUPluralRulesOffset);
|
|
VerifyObjectField(isolate, kICUDecimalFormatOffset);
|
|
}
|
|
|
|
void JSRelativeTimeFormat::JSRelativeTimeFormatVerify(Isolate* isolate) {
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kLocaleOffset);
|
|
VerifyObjectField(isolate, kICUFormatterOffset);
|
|
VerifyObjectField(isolate, kFlagsOffset);
|
|
}
|
|
|
|
void JSSegmentIterator::JSSegmentIteratorVerify(Isolate* isolate) {
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kICUBreakIteratorOffset);
|
|
VerifyObjectField(isolate, kUnicodeStringOffset);
|
|
VerifyObjectField(isolate, kFlagsOffset);
|
|
}
|
|
|
|
void JSSegmenter::JSSegmenterVerify(Isolate* isolate) {
|
|
JSObjectVerify(isolate);
|
|
VerifyObjectField(isolate, kLocaleOffset);
|
|
VerifyObjectField(isolate, kICUBreakIteratorOffset);
|
|
VerifyObjectField(isolate, kFlagsOffset);
|
|
}
|
|
#endif // V8_INTL_SUPPORT
|
|
|
|
#endif // VERIFY_HEAP
|
|
|
|
#ifdef DEBUG
|
|
|
|
void JSObject::IncrementSpillStatistics(Isolate* isolate,
|
|
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()->UnusedPropertyFields();
|
|
} else if (IsJSGlobalObject()) {
|
|
GlobalDictionary dict = JSGlobalObject::cast(*this)->global_dictionary();
|
|
info->number_of_slow_used_properties_ += dict->NumberOfElements();
|
|
info->number_of_slow_unused_properties_ +=
|
|
dict->Capacity() - dict->NumberOfElements();
|
|
} else {
|
|
NameDictionary 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 HOLEY_SMI_ELEMENTS:
|
|
case PACKED_SMI_ELEMENTS:
|
|
case HOLEY_DOUBLE_ELEMENTS:
|
|
case PACKED_DOUBLE_ELEMENTS:
|
|
case HOLEY_ELEMENTS:
|
|
case PACKED_ELEMENTS:
|
|
case FAST_STRING_WRAPPER_ELEMENTS: {
|
|
info->number_of_objects_with_fast_elements_++;
|
|
int holes = 0;
|
|
FixedArray e = FixedArray::cast(elements());
|
|
int len = e->length();
|
|
for (int i = 0; i < len; i++) {
|
|
if (e->get(i)->IsTheHole(isolate)) holes++;
|
|
}
|
|
info->number_of_fast_used_elements_ += len - holes;
|
|
info->number_of_fast_unused_elements_ += holes;
|
|
break;
|
|
}
|
|
|
|
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) case TYPE##_ELEMENTS:
|
|
|
|
TYPED_ARRAYS(TYPED_ARRAY_CASE)
|
|
#undef TYPED_ARRAY_CASE
|
|
{
|
|
info->number_of_objects_with_fast_elements_++;
|
|
FixedArrayBase e = FixedArrayBase::cast(elements());
|
|
info->number_of_fast_used_elements_ += e->length();
|
|
break;
|
|
}
|
|
case DICTIONARY_ELEMENTS:
|
|
case SLOW_STRING_WRAPPER_ELEMENTS: {
|
|
NumberDictionary dict = element_dictionary();
|
|
info->number_of_slow_used_elements_ += dict->NumberOfElements();
|
|
info->number_of_slow_unused_elements_ +=
|
|
dict->Capacity() - dict->NumberOfElements();
|
|
break;
|
|
}
|
|
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
|
|
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
|
|
case NO_ELEMENTS:
|
|
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(int valid_entries) {
|
|
if (valid_entries == -1) valid_entries = number_of_descriptors();
|
|
Name current_key;
|
|
uint32_t current = 0;
|
|
for (int i = 0; i < number_of_descriptors(); i++) {
|
|
Name key = GetSortedKey(i);
|
|
if (key == current_key) {
|
|
Print();
|
|
return false;
|
|
}
|
|
current_key = key;
|
|
uint32_t hash = GetSortedKey(i)->Hash();
|
|
if (hash < current) {
|
|
Print();
|
|
return false;
|
|
}
|
|
current = hash;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool TransitionArray::IsSortedNoDuplicates(int valid_entries) {
|
|
DCHECK_EQ(valid_entries, -1);
|
|
Name prev_key;
|
|
PropertyKind prev_kind = kData;
|
|
PropertyAttributes prev_attributes = NONE;
|
|
uint32_t prev_hash = 0;
|
|
|
|
for (int i = 0; i < number_of_transitions(); i++) {
|
|
Name key = GetSortedKey(i);
|
|
uint32_t hash = key->Hash();
|
|
PropertyKind kind = kData;
|
|
PropertyAttributes attributes = NONE;
|
|
if (!TransitionsAccessor::IsSpecialTransition(key->GetReadOnlyRoots(),
|
|
key)) {
|
|
Map target = GetTarget(i);
|
|
PropertyDetails details =
|
|
TransitionsAccessor::GetTargetDetails(key, target);
|
|
kind = details.kind();
|
|
attributes = details.attributes();
|
|
} else {
|
|
// Duplicate entries are not allowed for non-property transitions.
|
|
DCHECK_NE(prev_key, key);
|
|
}
|
|
|
|
int cmp = CompareKeys(prev_key, prev_hash, prev_kind, prev_attributes, key,
|
|
hash, kind, attributes);
|
|
if (cmp >= 0) {
|
|
Print();
|
|
return false;
|
|
}
|
|
prev_key = key;
|
|
prev_hash = hash;
|
|
prev_attributes = attributes;
|
|
prev_kind = kind;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool TransitionsAccessor::IsSortedNoDuplicates() {
|
|
// Simple and non-existent transitions are always sorted.
|
|
if (encoding() != kFullTransitionArray) return true;
|
|
return transitions()->IsSortedNoDuplicates();
|
|
}
|
|
|
|
static bool CheckOneBackPointer(Map current_map, Object* target) {
|
|
return !target->IsMap() || Map::cast(target)->GetBackPointer() == current_map;
|
|
}
|
|
|
|
bool TransitionsAccessor::IsConsistentWithBackPointers() {
|
|
int num_transitions = NumberOfTransitions();
|
|
for (int i = 0; i < num_transitions; i++) {
|
|
Map target = GetTarget(i);
|
|
if (!CheckOneBackPointer(map_, target)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|