ada64b58bf
Before Turbofan/Ignition it was possible to use external profilers to sample running V8/Node.js processes and generate reports/FlameGraphs from that. It's still possible to do so, but non-optimized JavaScript functions appear in the stack as InterpreterEntryTrampoline. This commit adds a runtime flag which makes interpreted frames visible on the process' native stack as distinguishable functions, making the sampled data gathered by external profilers such as Linux perf and DTrace more useful. R=bmeurer@google.com, franzih@google.com, jarin@google.com, yangguo@google.com Bug: v8:7155 Change-Id: I3dc8876aa3cd9f1b9766624842a7cc354ccca415 Reviewed-on: https://chromium-review.googlesource.com/959081 Commit-Queue: Yang Guo <yangguo@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#52533}
2247 lines
70 KiB
C++
2247 lines
70 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 <iomanip>
|
|
#include <memory>
|
|
|
|
#include "src/bootstrapper.h"
|
|
#include "src/disasm.h"
|
|
#include "src/disassembler.h"
|
|
#include "src/interpreter/bytecodes.h"
|
|
#include "src/objects-inl.h"
|
|
#include "src/objects/debug-objects-inl.h"
|
|
#include "src/objects/microtask-inl.h"
|
|
#include "src/objects/promise-inl.h"
|
|
#include "src/ostreams.h"
|
|
#include "src/regexp/jsregexp.h"
|
|
#include "src/transitions-inl.h"
|
|
#include "src/wasm/wasm-code-manager.h"
|
|
#include "src/wasm/wasm-engine.h"
|
|
#include "src/wasm/wasm-objects-inl.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
#ifdef OBJECT_PRINT
|
|
|
|
void Object::Print() {
|
|
OFStream os(stdout);
|
|
this->Print(os);
|
|
os << std::flush;
|
|
}
|
|
|
|
|
|
void Object::Print(std::ostream& os) { // NOLINT
|
|
if (IsSmi()) {
|
|
os << "Smi: " << std::hex << "0x" << Smi::ToInt(this);
|
|
os << std::dec << " (" << Smi::ToInt(this) << ")\n";
|
|
} else {
|
|
HeapObject::cast(this)->HeapObjectPrint(os);
|
|
}
|
|
}
|
|
|
|
void HeapObject::PrintHeader(std::ostream& os, const char* id) { // NOLINT
|
|
os << reinterpret_cast<void*>(this) << ": [";
|
|
if (id != nullptr) {
|
|
os << id;
|
|
} else {
|
|
os << map()->instance_type();
|
|
}
|
|
os << "]";
|
|
if (GetHeap()->InOldSpace(this)) os << " in OldSpace";
|
|
if (!IsMap()) os << "\n - map: " << Brief(map());
|
|
}
|
|
|
|
|
|
void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
|
|
InstanceType instance_type = map()->instance_type();
|
|
|
|
HandleScope scope(GetIsolate());
|
|
if (instance_type < FIRST_NONSTRING_TYPE) {
|
|
String::cast(this)->StringPrint(os);
|
|
os << "\n";
|
|
return;
|
|
}
|
|
|
|
switch (instance_type) {
|
|
case SYMBOL_TYPE:
|
|
Symbol::cast(this)->SymbolPrint(os);
|
|
break;
|
|
case MAP_TYPE:
|
|
Map::cast(this)->MapPrint(os);
|
|
break;
|
|
case HEAP_NUMBER_TYPE:
|
|
HeapNumber::cast(this)->HeapNumberPrint(os);
|
|
os << "\n";
|
|
break;
|
|
case MUTABLE_HEAP_NUMBER_TYPE:
|
|
os << "<mutable ";
|
|
HeapNumber::cast(this)->HeapNumberPrint(os);
|
|
os << ">\n";
|
|
break;
|
|
case BIGINT_TYPE:
|
|
BigInt::cast(this)->BigIntPrint(os);
|
|
os << "\n";
|
|
break;
|
|
case FIXED_DOUBLE_ARRAY_TYPE:
|
|
FixedDoubleArray::cast(this)->FixedDoubleArrayPrint(os);
|
|
break;
|
|
case HASH_TABLE_TYPE:
|
|
case FIXED_ARRAY_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 NATIVE_CONTEXT_TYPE:
|
|
case SCRIPT_CONTEXT_TYPE:
|
|
case WITH_CONTEXT_TYPE:
|
|
FixedArray::cast(this)->FixedArrayPrint(os);
|
|
break;
|
|
case BOILERPLATE_DESCRIPTION_TYPE:
|
|
BoilerplateDescription::cast(this)->BoilerplateDescriptionPrint(os);
|
|
break;
|
|
case PROPERTY_ARRAY_TYPE:
|
|
PropertyArray::cast(this)->PropertyArrayPrint(os);
|
|
break;
|
|
case BYTE_ARRAY_TYPE:
|
|
ByteArray::cast(this)->ByteArrayPrint(os);
|
|
break;
|
|
case BYTECODE_ARRAY_TYPE:
|
|
BytecodeArray::cast(this)->BytecodeArrayPrint(os);
|
|
break;
|
|
case DESCRIPTOR_ARRAY_TYPE:
|
|
DescriptorArray::cast(this)->PrintDescriptors(os);
|
|
break;
|
|
case TRANSITION_ARRAY_TYPE:
|
|
TransitionArray::cast(this)->TransitionArrayPrint(os);
|
|
break;
|
|
case FEEDBACK_CELL_TYPE:
|
|
FeedbackCell::cast(this)->FeedbackCellPrint(os);
|
|
break;
|
|
case FEEDBACK_VECTOR_TYPE:
|
|
FeedbackVector::cast(this)->FeedbackVectorPrint(os);
|
|
break;
|
|
case FREE_SPACE_TYPE:
|
|
FreeSpace::cast(this)->FreeSpacePrint(os);
|
|
break;
|
|
|
|
#define PRINT_FIXED_TYPED_ARRAY(Type, type, TYPE, ctype, size) \
|
|
case Fixed##Type##Array::kInstanceType: \
|
|
Fixed##Type##Array::cast(this)->FixedTypedArrayPrint(os); \
|
|
break;
|
|
|
|
TYPED_ARRAYS(PRINT_FIXED_TYPED_ARRAY)
|
|
#undef PRINT_FIXED_TYPED_ARRAY
|
|
|
|
case FILLER_TYPE:
|
|
os << "filler";
|
|
break;
|
|
case JS_OBJECT_TYPE: // fall through
|
|
case JS_API_OBJECT_TYPE:
|
|
case JS_SPECIAL_API_OBJECT_TYPE:
|
|
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
|
|
case JS_GENERATOR_OBJECT_TYPE:
|
|
case JS_ASYNC_GENERATOR_OBJECT_TYPE:
|
|
case JS_ARGUMENTS_TYPE:
|
|
case JS_ERROR_TYPE:
|
|
case WASM_GLOBAL_TYPE:
|
|
case WASM_INSTANCE_TYPE: // TODO(titzer): debug printing for wasm objects
|
|
case WASM_MEMORY_TYPE:
|
|
case WASM_MODULE_TYPE:
|
|
case WASM_TABLE_TYPE:
|
|
JSObject::cast(this)->JSObjectPrint(os);
|
|
break;
|
|
case JS_PROMISE_TYPE:
|
|
JSPromise::cast(this)->JSPromisePrint(os);
|
|
break;
|
|
case JS_ARRAY_TYPE:
|
|
JSArray::cast(this)->JSArrayPrint(os);
|
|
break;
|
|
case JS_REGEXP_TYPE:
|
|
JSRegExp::cast(this)->JSRegExpPrint(os);
|
|
break;
|
|
case JS_REGEXP_STRING_ITERATOR_TYPE:
|
|
JSRegExpStringIterator::cast(this)->JSRegExpStringIteratorPrint(os);
|
|
break;
|
|
case ODDBALL_TYPE:
|
|
Oddball::cast(this)->to_string()->Print(os);
|
|
break;
|
|
case JS_BOUND_FUNCTION_TYPE:
|
|
JSBoundFunction::cast(this)->JSBoundFunctionPrint(os);
|
|
break;
|
|
case JS_FUNCTION_TYPE:
|
|
JSFunction::cast(this)->JSFunctionPrint(os);
|
|
break;
|
|
case JS_GLOBAL_PROXY_TYPE:
|
|
JSGlobalProxy::cast(this)->JSGlobalProxyPrint(os);
|
|
break;
|
|
case JS_GLOBAL_OBJECT_TYPE:
|
|
JSGlobalObject::cast(this)->JSGlobalObjectPrint(os);
|
|
break;
|
|
case JS_VALUE_TYPE:
|
|
JSValue::cast(this)->JSValuePrint(os);
|
|
break;
|
|
case JS_DATE_TYPE:
|
|
JSDate::cast(this)->JSDatePrint(os);
|
|
break;
|
|
case CODE_TYPE:
|
|
Code::cast(this)->CodePrint(os);
|
|
break;
|
|
case CODE_DATA_CONTAINER_TYPE:
|
|
CodeDataContainer::cast(this)->CodeDataContainerPrint(os);
|
|
break;
|
|
case JS_PROXY_TYPE:
|
|
JSProxy::cast(this)->JSProxyPrint(os);
|
|
break;
|
|
case JS_SET_TYPE:
|
|
JSSet::cast(this)->JSSetPrint(os);
|
|
break;
|
|
case JS_MAP_TYPE:
|
|
JSMap::cast(this)->JSMapPrint(os);
|
|
break;
|
|
case JS_SET_KEY_VALUE_ITERATOR_TYPE:
|
|
case JS_SET_VALUE_ITERATOR_TYPE:
|
|
JSSetIterator::cast(this)->JSSetIteratorPrint(os);
|
|
break;
|
|
case JS_MAP_KEY_ITERATOR_TYPE:
|
|
case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
|
|
case JS_MAP_VALUE_ITERATOR_TYPE:
|
|
JSMapIterator::cast(this)->JSMapIteratorPrint(os);
|
|
break;
|
|
case JS_WEAK_MAP_TYPE:
|
|
JSWeakMap::cast(this)->JSWeakMapPrint(os);
|
|
break;
|
|
case JS_WEAK_SET_TYPE:
|
|
JSWeakSet::cast(this)->JSWeakSetPrint(os);
|
|
break;
|
|
case JS_MODULE_NAMESPACE_TYPE:
|
|
JSModuleNamespace::cast(this)->JSModuleNamespacePrint(os);
|
|
break;
|
|
case FOREIGN_TYPE:
|
|
Foreign::cast(this)->ForeignPrint(os);
|
|
break;
|
|
case CALL_HANDLER_INFO_TYPE:
|
|
CallHandlerInfo::cast(this)->CallHandlerInfoPrint(os);
|
|
break;
|
|
case SHARED_FUNCTION_INFO_TYPE:
|
|
SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(os);
|
|
break;
|
|
case JS_MESSAGE_OBJECT_TYPE:
|
|
JSMessageObject::cast(this)->JSMessageObjectPrint(os);
|
|
break;
|
|
case CELL_TYPE:
|
|
Cell::cast(this)->CellPrint(os);
|
|
break;
|
|
case PROPERTY_CELL_TYPE:
|
|
PropertyCell::cast(this)->PropertyCellPrint(os);
|
|
break;
|
|
case WEAK_CELL_TYPE:
|
|
WeakCell::cast(this)->WeakCellPrint(os);
|
|
break;
|
|
case JS_ARRAY_BUFFER_TYPE:
|
|
JSArrayBuffer::cast(this)->JSArrayBufferPrint(os);
|
|
break;
|
|
case JS_ARRAY_ITERATOR_TYPE:
|
|
JSArrayIterator::cast(this)->JSArrayIteratorPrint(os);
|
|
break;
|
|
case JS_TYPED_ARRAY_TYPE:
|
|
JSTypedArray::cast(this)->JSTypedArrayPrint(os);
|
|
break;
|
|
case JS_DATA_VIEW_TYPE:
|
|
JSDataView::cast(this)->JSDataViewPrint(os);
|
|
break;
|
|
#define MAKE_STRUCT_CASE(NAME, Name, name) \
|
|
case NAME##_TYPE: \
|
|
Name::cast(this)->Name##Print(os); \
|
|
break;
|
|
STRUCT_LIST(MAKE_STRUCT_CASE)
|
|
#undef MAKE_STRUCT_CASE
|
|
|
|
case LOAD_HANDLER_TYPE:
|
|
LoadHandler::cast(this)->LoadHandlerPrint(os);
|
|
break;
|
|
case STORE_HANDLER_TYPE:
|
|
StoreHandler::cast(this)->StoreHandlerPrint(os);
|
|
break;
|
|
case SCOPE_INFO_TYPE:
|
|
ScopeInfo::cast(this)->ScopeInfoPrint(os);
|
|
break;
|
|
case FEEDBACK_METADATA_TYPE:
|
|
FeedbackMetadata::cast(this)->FeedbackMetadataPrint(os);
|
|
break;
|
|
case WEAK_FIXED_ARRAY_TYPE:
|
|
WeakFixedArray::cast(this)->WeakFixedArrayPrint(os);
|
|
break;
|
|
case INTERNALIZED_STRING_TYPE:
|
|
case EXTERNAL_INTERNALIZED_STRING_TYPE:
|
|
case ONE_BYTE_INTERNALIZED_STRING_TYPE:
|
|
case EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE:
|
|
case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
|
|
case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE:
|
|
case SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE:
|
|
case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
|
|
case STRING_TYPE:
|
|
case CONS_STRING_TYPE:
|
|
case EXTERNAL_STRING_TYPE:
|
|
case SLICED_STRING_TYPE:
|
|
case THIN_STRING_TYPE:
|
|
case ONE_BYTE_STRING_TYPE:
|
|
case CONS_ONE_BYTE_STRING_TYPE:
|
|
case EXTERNAL_ONE_BYTE_STRING_TYPE:
|
|
case SLICED_ONE_BYTE_STRING_TYPE:
|
|
case THIN_ONE_BYTE_STRING_TYPE:
|
|
case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
|
|
case SHORT_EXTERNAL_STRING_TYPE:
|
|
case SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE:
|
|
case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
|
|
case SMALL_ORDERED_HASH_MAP_TYPE:
|
|
case SMALL_ORDERED_HASH_SET_TYPE:
|
|
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
|
|
case JS_STRING_ITERATOR_TYPE:
|
|
// TODO(all): Handle these types too.
|
|
os << "UNKNOWN TYPE " << map()->instance_type();
|
|
UNREACHABLE();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ByteArray::ByteArrayPrint(std::ostream& os) { // NOLINT
|
|
os << "byte array, data starts at " << GetDataStartAddress();
|
|
}
|
|
|
|
|
|
void BytecodeArray::BytecodeArrayPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "BytecodeArray");
|
|
Disassemble(os);
|
|
}
|
|
|
|
|
|
void FreeSpace::FreeSpacePrint(std::ostream& os) { // NOLINT
|
|
os << "free space, size " << Size();
|
|
}
|
|
|
|
|
|
template <class Traits>
|
|
void FixedTypedArray<Traits>::FixedTypedArrayPrint(
|
|
std::ostream& os) { // NOLINT
|
|
os << "fixed " << Traits::Designator();
|
|
}
|
|
|
|
bool JSObject::PrintProperties(std::ostream& os) { // NOLINT
|
|
if (HasFastProperties()) {
|
|
DescriptorArray* descs = map()->instance_descriptors();
|
|
int nof_inobject_properties = map()->GetInObjectProperties();
|
|
int i = 0;
|
|
for (; i < map()->NumberOfOwnDescriptors(); i++) {
|
|
os << "\n ";
|
|
descs->GetKey(i)->NamePrint(os);
|
|
os << ": ";
|
|
PropertyDetails details = descs->GetDetails(i);
|
|
switch (details.location()) {
|
|
case kField: {
|
|
FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
|
|
if (IsUnboxedDoubleField(field_index)) {
|
|
os << "<unboxed double> " << RawFastDoublePropertyAt(field_index);
|
|
} else {
|
|
os << Brief(RawFastPropertyAt(field_index));
|
|
}
|
|
break;
|
|
}
|
|
case kDescriptor:
|
|
os << Brief(descs->GetValue(i));
|
|
break;
|
|
}
|
|
os << " ";
|
|
details.PrintAsFastTo(os, PropertyDetails::kForProperties);
|
|
if (details.location() != kField) continue;
|
|
int field_index = details.field_index();
|
|
if (nof_inobject_properties <= field_index) {
|
|
field_index -= nof_inobject_properties;
|
|
os << " properties[" << field_index << "]";
|
|
}
|
|
}
|
|
return i > 0;
|
|
} else if (IsJSGlobalObject()) {
|
|
JSGlobalObject::cast(this)->global_dictionary()->Print(os);
|
|
} else {
|
|
property_dictionary()->Print(os);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
namespace {
|
|
|
|
template <class T>
|
|
bool IsTheHoleAt(T* array, int index) {
|
|
return false;
|
|
}
|
|
|
|
template <>
|
|
bool IsTheHoleAt(FixedDoubleArray* array, int index) {
|
|
return array->is_the_hole(index);
|
|
}
|
|
|
|
template <class T>
|
|
double GetScalarElement(T* array, int index) {
|
|
if (IsTheHoleAt(array, index)) {
|
|
return std::numeric_limits<double>::quiet_NaN();
|
|
}
|
|
return array->get_scalar(index);
|
|
}
|
|
|
|
template <class T>
|
|
void DoPrintElements(std::ostream& os, Object* object) { // NOLINT
|
|
const bool print_the_hole = std::is_same<T, FixedDoubleArray>::value;
|
|
T* array = T::cast(object);
|
|
if (array->length() == 0) return;
|
|
int previous_index = 0;
|
|
double previous_value = GetScalarElement(array, 0);
|
|
double value = 0.0;
|
|
int i;
|
|
for (i = 1; i <= array->length(); i++) {
|
|
if (i < array->length()) value = GetScalarElement(array, i);
|
|
bool values_are_nan = std::isnan(previous_value) && std::isnan(value);
|
|
if (i != array->length() && (previous_value == value || values_are_nan) &&
|
|
IsTheHoleAt(array, i - 1) == IsTheHoleAt(array, i)) {
|
|
continue;
|
|
}
|
|
os << "\n";
|
|
std::stringstream ss;
|
|
ss << previous_index;
|
|
if (previous_index != i - 1) {
|
|
ss << '-' << (i - 1);
|
|
}
|
|
os << std::setw(12) << ss.str() << ": ";
|
|
if (print_the_hole && IsTheHoleAt(array, i - 1)) {
|
|
os << "<the_hole>";
|
|
} else {
|
|
os << previous_value;
|
|
}
|
|
previous_index = i;
|
|
previous_value = value;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void PrintFixedArrayElements(std::ostream& os, T* array) {
|
|
// Print in array notation for non-sparse arrays.
|
|
Object* previous_value = array->length() > 0 ? array->get(0) : nullptr;
|
|
Object* value = nullptr;
|
|
int previous_index = 0;
|
|
int i;
|
|
for (i = 1; i <= array->length(); i++) {
|
|
if (i < array->length()) value = array->get(i);
|
|
if (previous_value == value && i != array->length()) {
|
|
continue;
|
|
}
|
|
os << "\n";
|
|
std::stringstream ss;
|
|
ss << previous_index;
|
|
if (previous_index != i - 1) {
|
|
ss << '-' << (i - 1);
|
|
}
|
|
os << std::setw(12) << ss.str() << ": " << Brief(previous_value);
|
|
previous_index = i;
|
|
previous_value = value;
|
|
}
|
|
}
|
|
|
|
void PrintDictionaryElements(std::ostream& os, FixedArrayBase* elements) {
|
|
// Print some internal fields
|
|
NumberDictionary* dict = NumberDictionary::cast(elements);
|
|
if (dict->requires_slow_elements()) {
|
|
os << "\n - requires_slow_elements";
|
|
} else {
|
|
os << "\n - max_number_key: " << dict->max_number_key();
|
|
}
|
|
dict->Print(os);
|
|
}
|
|
|
|
void PrintSloppyArgumentElements(std::ostream& os, ElementsKind kind,
|
|
SloppyArgumentsElements* elements) {
|
|
Isolate* isolate = elements->GetIsolate();
|
|
FixedArray* arguments_store = elements->arguments();
|
|
os << "\n 0: context: " << Brief(elements->context())
|
|
<< "\n 1: arguments_store: " << Brief(arguments_store)
|
|
<< "\n parameter to context slot map:";
|
|
for (uint32_t i = 0; i < elements->parameter_map_length(); i++) {
|
|
uint32_t raw_index = i + SloppyArgumentsElements::kParameterMapStart;
|
|
Object* mapped_entry = elements->get_mapped_entry(i);
|
|
os << "\n " << raw_index << ": param(" << i
|
|
<< "): " << Brief(mapped_entry);
|
|
if (mapped_entry->IsTheHole(isolate)) {
|
|
os << " in the arguments_store[" << i << "]";
|
|
} else {
|
|
os << " in the context";
|
|
}
|
|
}
|
|
if (arguments_store->length() == 0) return;
|
|
os << "\n }"
|
|
<< "\n - arguments_store: " << Brief(arguments_store) << " "
|
|
<< ElementsKindToString(arguments_store->map()->elements_kind()) << " {";
|
|
if (kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
|
|
PrintFixedArrayElements(os, arguments_store);
|
|
} else {
|
|
DCHECK_EQ(kind, SLOW_SLOPPY_ARGUMENTS_ELEMENTS);
|
|
PrintDictionaryElements(os, arguments_store);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void JSObject::PrintElements(std::ostream& os) { // NOLINT
|
|
// Don't call GetElementsKind, its validation code can cause the printer to
|
|
// fail when debugging.
|
|
os << " - elements: " << Brief(elements()) << " {";
|
|
if (elements()->length() == 0) {
|
|
os << " }\n";
|
|
return;
|
|
}
|
|
switch (map()->elements_kind()) {
|
|
case HOLEY_SMI_ELEMENTS:
|
|
case PACKED_SMI_ELEMENTS:
|
|
case HOLEY_ELEMENTS:
|
|
case PACKED_ELEMENTS:
|
|
case FAST_STRING_WRAPPER_ELEMENTS: {
|
|
PrintFixedArrayElements(os, FixedArray::cast(elements()));
|
|
break;
|
|
}
|
|
case HOLEY_DOUBLE_ELEMENTS:
|
|
case PACKED_DOUBLE_ELEMENTS: {
|
|
DoPrintElements<FixedDoubleArray>(os, elements());
|
|
break;
|
|
}
|
|
|
|
#define PRINT_ELEMENTS(Type, type, TYPE, elementType, size) \
|
|
case TYPE##_ELEMENTS: { \
|
|
DoPrintElements<Fixed##Type##Array>(os, elements()); \
|
|
break; \
|
|
}
|
|
TYPED_ARRAYS(PRINT_ELEMENTS)
|
|
#undef PRINT_ELEMENTS
|
|
|
|
case DICTIONARY_ELEMENTS:
|
|
case SLOW_STRING_WRAPPER_ELEMENTS:
|
|
PrintDictionaryElements(os, elements());
|
|
break;
|
|
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
|
|
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
|
|
PrintSloppyArgumentElements(os, map()->elements_kind(),
|
|
SloppyArgumentsElements::cast(elements()));
|
|
break;
|
|
case NO_ELEMENTS:
|
|
break;
|
|
}
|
|
os << "\n }\n";
|
|
}
|
|
|
|
|
|
static void JSObjectPrintHeader(std::ostream& os, JSObject* obj,
|
|
const char* id) { // NOLINT
|
|
obj->PrintHeader(os, id);
|
|
// Don't call GetElementsKind, its validation code can cause the printer to
|
|
// fail when debugging.
|
|
os << " [";
|
|
if (obj->HasFastProperties()) {
|
|
os << "FastProperties";
|
|
} else {
|
|
os << "DictionaryProperties";
|
|
}
|
|
PrototypeIterator iter(obj->GetIsolate(), obj);
|
|
os << "]\n - prototype: " << Brief(iter.GetCurrent());
|
|
os << "\n - elements: " << Brief(obj->elements()) << " ["
|
|
<< ElementsKindToString(obj->map()->elements_kind());
|
|
if (obj->elements()->IsCowArray()) os << " (COW)";
|
|
os << "]";
|
|
Object* hash = obj->GetHash();
|
|
if (hash->IsSmi()) {
|
|
os << "\n - hash: " << Brief(hash);
|
|
}
|
|
if (obj->GetEmbedderFieldCount() > 0) {
|
|
os << "\n - embedder fields: " << obj->GetEmbedderFieldCount();
|
|
}
|
|
}
|
|
|
|
|
|
static void JSObjectPrintBody(std::ostream& os, JSObject* obj, // NOLINT
|
|
bool print_elements = true) {
|
|
os << "\n - properties: ";
|
|
Object* properties_or_hash = obj->raw_properties_or_hash();
|
|
if (!properties_or_hash->IsSmi()) {
|
|
os << Brief(properties_or_hash);
|
|
}
|
|
os << " {";
|
|
if (obj->PrintProperties(os)) os << "\n ";
|
|
os << "}\n";
|
|
if (print_elements && obj->elements()->length() > 0) {
|
|
obj->PrintElements(os);
|
|
}
|
|
int embedder_fields = obj->GetEmbedderFieldCount();
|
|
if (embedder_fields > 0) {
|
|
os << " - embedder fields = {";
|
|
for (int i = 0; i < embedder_fields; i++) {
|
|
os << "\n " << obj->GetEmbedderField(i);
|
|
}
|
|
os << "\n }\n";
|
|
}
|
|
}
|
|
|
|
|
|
void JSObject::JSObjectPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, nullptr);
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
void JSArray::JSArrayPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSArray");
|
|
os << "\n - length: " << Brief(this->length());
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
void JSPromise::JSPromisePrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSPromise");
|
|
os << "\n - status: " << JSPromise::Status(status());
|
|
if (status() == Promise::kPending) {
|
|
os << "\n - reactions: " << Brief(reactions());
|
|
} else {
|
|
os << "\n - result: " << Brief(result());
|
|
}
|
|
os << "\n - has_handler: " << has_handler();
|
|
os << "\n ";
|
|
}
|
|
|
|
void JSRegExp::JSRegExpPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSRegExp");
|
|
os << "\n - data: " << Brief(data());
|
|
os << "\n - source: " << Brief(source());
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
void JSRegExpStringIterator::JSRegExpStringIteratorPrint(
|
|
std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSRegExpStringIterator");
|
|
os << "\n - regex: " << Brief(iterating_regexp());
|
|
os << "\n - string: " << Brief(iterating_string());
|
|
os << "\n - done: " << done();
|
|
os << "\n - global: " << global();
|
|
os << "\n - unicode: " << unicode();
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
void Symbol::SymbolPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "Symbol");
|
|
os << "\n - hash: " << Hash();
|
|
os << "\n - name: " << Brief(name());
|
|
if (name()->IsUndefined(GetIsolate())) {
|
|
os << " (" << PrivateSymbolToName() << ")";
|
|
}
|
|
os << "\n - private: " << is_private();
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void Map::MapPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "Map");
|
|
os << "\n - type: " << instance_type();
|
|
os << "\n - instance size: ";
|
|
if (instance_size() == kVariableSizeSentinel) {
|
|
os << "variable";
|
|
} else {
|
|
os << instance_size();
|
|
}
|
|
if (IsJSObjectMap()) {
|
|
os << "\n - inobject properties: " << GetInObjectProperties();
|
|
}
|
|
os << "\n - elements kind: " << ElementsKindToString(elements_kind());
|
|
os << "\n - unused property fields: " << UnusedPropertyFields();
|
|
os << "\n - enum length: ";
|
|
if (EnumLength() == kInvalidEnumCacheSentinel) {
|
|
os << "invalid";
|
|
} else {
|
|
os << EnumLength();
|
|
}
|
|
if (is_deprecated()) os << "\n - deprecated_map";
|
|
if (is_stable()) os << "\n - stable_map";
|
|
if (is_migration_target()) os << "\n - migration_target";
|
|
if (is_dictionary_map()) os << "\n - dictionary_map";
|
|
if (has_hidden_prototype()) os << "\n - has_hidden_prototype";
|
|
if (has_named_interceptor()) os << "\n - named_interceptor";
|
|
if (has_indexed_interceptor()) os << "\n - indexed_interceptor";
|
|
if (may_have_interesting_symbols()) os << "\n - may_have_interesting_symbols";
|
|
if (is_undetectable()) os << "\n - undetectable";
|
|
if (is_callable()) os << "\n - callable";
|
|
if (is_constructor()) os << "\n - constructor";
|
|
if (has_prototype_slot()) {
|
|
os << "\n - has_prototype_slot";
|
|
if (has_non_instance_prototype()) os << " (non-instance prototype)";
|
|
}
|
|
if (is_access_check_needed()) os << "\n - access_check_needed";
|
|
if (!is_extensible()) os << "\n - non-extensible";
|
|
if (is_prototype_map()) {
|
|
os << "\n - prototype_map";
|
|
os << "\n - prototype info: " << Brief(prototype_info());
|
|
} else {
|
|
os << "\n - back pointer: " << Brief(GetBackPointer());
|
|
}
|
|
os << "\n - prototype_validity cell: " << Brief(prototype_validity_cell());
|
|
os << "\n - instance descriptors " << (owns_descriptors() ? "(own) " : "")
|
|
<< "#" << NumberOfOwnDescriptors() << ": "
|
|
<< Brief(instance_descriptors());
|
|
if (FLAG_unbox_double_fields) {
|
|
os << "\n - layout descriptor: ";
|
|
layout_descriptor()->ShortPrint(os);
|
|
}
|
|
{
|
|
DisallowHeapAllocation no_gc;
|
|
TransitionsAccessor transitions(this, &no_gc);
|
|
int nof_transitions = transitions.NumberOfTransitions();
|
|
if (nof_transitions > 0) {
|
|
os << "\n - transitions #" << nof_transitions << ": ";
|
|
HeapObject* heap_object;
|
|
Smi* smi;
|
|
if (raw_transitions()->ToSmi(&smi)) {
|
|
os << Brief(smi);
|
|
} else if (raw_transitions()->ToStrongOrWeakHeapObject(&heap_object)) {
|
|
os << Brief(heap_object);
|
|
}
|
|
transitions.PrintTransitions(os);
|
|
}
|
|
}
|
|
os << "\n - prototype: " << Brief(prototype());
|
|
os << "\n - constructor: " << Brief(GetConstructor());
|
|
os << "\n - dependent code: " << Brief(dependent_code());
|
|
os << "\n - construction counter: " << construction_counter();
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void AliasedArgumentsEntry::AliasedArgumentsEntryPrint(
|
|
std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "AliasedArgumentsEntry");
|
|
os << "\n - aliased_context_slot: " << aliased_context_slot();
|
|
}
|
|
|
|
namespace {
|
|
void PrintFixedArrayWithHeader(std::ostream& os, FixedArray* array,
|
|
const char* type) {
|
|
array->PrintHeader(os, type);
|
|
os << "\n - length: " << array->length();
|
|
PrintFixedArrayElements(os, array);
|
|
os << "\n";
|
|
}
|
|
|
|
void PrintWeakFixedArrayElements(std::ostream& os, WeakFixedArray* array) {
|
|
// Print in array notation for non-sparse arrays.
|
|
MaybeObject* previous_value = array->length() > 0 ? array->Get(0) : nullptr;
|
|
MaybeObject* value = nullptr;
|
|
int previous_index = 0;
|
|
int i;
|
|
for (i = 1; i <= array->length(); i++) {
|
|
if (i < array->length()) value = array->Get(i);
|
|
if (previous_value == value && i != array->length()) {
|
|
continue;
|
|
}
|
|
os << "\n";
|
|
std::stringstream ss;
|
|
ss << previous_index;
|
|
if (previous_index != i - 1) {
|
|
ss << '-' << (i - 1);
|
|
}
|
|
os << std::setw(12) << ss.str() << ": " << MaybeObjectBrief(previous_value);
|
|
previous_index = i;
|
|
previous_value = value;
|
|
}
|
|
}
|
|
|
|
void PrintWeakFixedArrayWithHeader(std::ostream& os, WeakFixedArray* array) {
|
|
array->PrintHeader(os, "WeakFixedArray");
|
|
os << "\n - length: " << array->length() << "\n";
|
|
PrintWeakFixedArrayElements(os, array);
|
|
os << "\n";
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void FixedArray::FixedArrayPrint(std::ostream& os) { // NOLINT
|
|
PrintFixedArrayWithHeader(os, this,
|
|
IsHashTable() ? "HashTable" : "FixedArray");
|
|
}
|
|
|
|
void BoilerplateDescription::BoilerplateDescriptionPrint(std::ostream& os) {
|
|
PrintFixedArrayWithHeader(os, this, "BoilerplateDescription");
|
|
}
|
|
|
|
void PropertyArray::PropertyArrayPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "PropertyArray");
|
|
os << "\n - length: " << length();
|
|
os << "\n - hash: " << Hash();
|
|
PrintFixedArrayElements(os, this);
|
|
os << "\n";
|
|
}
|
|
|
|
void FixedDoubleArray::FixedDoubleArrayPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "FixedDoubleArray");
|
|
os << "\n - length: " << length();
|
|
DoPrintElements<FixedDoubleArray>(os, this);
|
|
os << "\n";
|
|
}
|
|
|
|
void WeakFixedArray::WeakFixedArrayPrint(std::ostream& os) {
|
|
PrintWeakFixedArrayWithHeader(os, this);
|
|
}
|
|
|
|
void TransitionArray::TransitionArrayPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "TransitionArray");
|
|
os << "\n - capacity: " << length();
|
|
for (int i = 0; i < length(); i++) {
|
|
os << "\n [" << i << "]: " << Brief(get(i));
|
|
if (i == kPrototypeTransitionsIndex) os << " (prototype transitions)";
|
|
if (i == kTransitionLengthIndex) os << " (number of transitions)";
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
void FeedbackCell::FeedbackCellPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "FeedbackCell");
|
|
if (map() == GetHeap()->no_closures_cell_map()) {
|
|
os << "\n - no closures";
|
|
} else if (map() == GetHeap()->one_closure_cell_map()) {
|
|
os << "\n - one closure";
|
|
} else if (map() == GetHeap()->many_closures_cell_map()) {
|
|
os << "\n - many closures";
|
|
} else {
|
|
os << "\n - Invalid FeedbackCell map";
|
|
}
|
|
os << " - value: " << Brief(value());
|
|
os << "\n";
|
|
}
|
|
|
|
void FeedbackVectorSpec::Print() {
|
|
OFStream os(stdout);
|
|
|
|
FeedbackVectorSpecPrint(os);
|
|
|
|
os << std::flush;
|
|
}
|
|
|
|
void FeedbackVectorSpec::FeedbackVectorSpecPrint(std::ostream& os) { // NOLINT
|
|
int slot_count = slots();
|
|
os << " - slot_count: " << slot_count;
|
|
if (slot_count == 0) {
|
|
os << " (empty)\n";
|
|
return;
|
|
}
|
|
|
|
for (int slot = 0; slot < slot_count;) {
|
|
FeedbackSlotKind kind = GetKind(FeedbackSlot(slot));
|
|
int entry_size = FeedbackMetadata::GetSlotSize(kind);
|
|
DCHECK_LT(0, entry_size);
|
|
os << "\n Slot #" << slot << " " << kind;
|
|
slot += entry_size;
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
void FeedbackMetadata::Print() {
|
|
OFStream os(stdout);
|
|
FeedbackMetadataPrint(os);
|
|
os << std::flush;
|
|
}
|
|
|
|
void FeedbackMetadata::FeedbackMetadataPrint(std::ostream& os) {
|
|
HeapObject::PrintHeader(os, "FeedbackMetadata");
|
|
os << "\n - slot_count: " << slot_count();
|
|
|
|
FeedbackMetadataIterator iter(this);
|
|
while (iter.HasNext()) {
|
|
FeedbackSlot slot = iter.Next();
|
|
FeedbackSlotKind kind = iter.kind();
|
|
os << "\n Slot " << slot << " " << kind;
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
void FeedbackVector::Print() {
|
|
OFStream os(stdout);
|
|
FeedbackVectorPrint(os);
|
|
os << std::flush;
|
|
}
|
|
|
|
void FeedbackVector::FeedbackVectorPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "FeedbackVector");
|
|
os << "\n - length: " << length();
|
|
if (length() == 0) {
|
|
os << " (empty)\n";
|
|
return;
|
|
}
|
|
|
|
os << "\n - shared function info: " << Brief(shared_function_info());
|
|
os << "\n - optimized code/marker: ";
|
|
if (has_optimized_code()) {
|
|
os << Brief(optimized_code());
|
|
} else {
|
|
os << optimization_marker();
|
|
}
|
|
os << "\n - invocation count: " << invocation_count();
|
|
os << "\n - profiler ticks: " << profiler_ticks();
|
|
|
|
FeedbackMetadataIterator iter(metadata());
|
|
while (iter.HasNext()) {
|
|
FeedbackSlot slot = iter.Next();
|
|
FeedbackSlotKind kind = iter.kind();
|
|
|
|
os << "\n - slot " << slot << " " << kind << " ";
|
|
FeedbackSlotPrint(os, slot);
|
|
|
|
int entry_size = iter.entry_size();
|
|
if (entry_size > 0) os << " {";
|
|
for (int i = 0; i < entry_size; i++) {
|
|
int index = GetIndex(slot) + i;
|
|
os << "\n [" << index << "]: " << Brief(get(index));
|
|
}
|
|
if (entry_size > 0) os << "\n }";
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
void FeedbackVector::FeedbackSlotPrint(std::ostream& os,
|
|
FeedbackSlot slot) { // NOLINT
|
|
FeedbackNexus nexus(this, slot);
|
|
nexus.Print(os);
|
|
}
|
|
|
|
namespace {
|
|
|
|
const char* ICState2String(InlineCacheState state) {
|
|
switch (state) {
|
|
case UNINITIALIZED:
|
|
return "UNINITIALIZED";
|
|
case PREMONOMORPHIC:
|
|
return "PREMONOMORPHIC";
|
|
case MONOMORPHIC:
|
|
return "MONOMORPHIC";
|
|
case RECOMPUTE_HANDLER:
|
|
return "RECOMPUTE_HANDLER";
|
|
case POLYMORPHIC:
|
|
return "POLYMORPHIC";
|
|
case MEGAMORPHIC:
|
|
return "MEGAMORPHIC";
|
|
case GENERIC:
|
|
return "GENERIC";
|
|
}
|
|
UNREACHABLE();
|
|
}
|
|
} // anonymous namespace
|
|
|
|
void FeedbackNexus::Print(std::ostream& os) { // NOLINT
|
|
switch (kind()) {
|
|
case FeedbackSlotKind::kCall:
|
|
case FeedbackSlotKind::kLoadProperty:
|
|
case FeedbackSlotKind::kLoadKeyed:
|
|
case FeedbackSlotKind::kLoadGlobalInsideTypeof:
|
|
case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
|
|
case FeedbackSlotKind::kStoreNamedSloppy:
|
|
case FeedbackSlotKind::kStoreNamedStrict:
|
|
case FeedbackSlotKind::kStoreOwnNamed:
|
|
case FeedbackSlotKind::kStoreGlobalSloppy:
|
|
case FeedbackSlotKind::kStoreGlobalStrict:
|
|
case FeedbackSlotKind::kStoreKeyedSloppy:
|
|
case FeedbackSlotKind::kInstanceOf:
|
|
case FeedbackSlotKind::kStoreDataPropertyInLiteral:
|
|
case FeedbackSlotKind::kStoreKeyedStrict:
|
|
case FeedbackSlotKind::kStoreInArrayLiteral: {
|
|
os << ICState2String(StateFromFeedback());
|
|
break;
|
|
}
|
|
case FeedbackSlotKind::kBinaryOp: {
|
|
os << "BinaryOp:" << GetBinaryOperationFeedback();
|
|
break;
|
|
}
|
|
case FeedbackSlotKind::kCompareOp: {
|
|
os << "CompareOp:" << GetCompareOperationFeedback();
|
|
break;
|
|
}
|
|
case FeedbackSlotKind::kForIn: {
|
|
os << "ForIn:" << GetForInFeedback();
|
|
break;
|
|
}
|
|
case FeedbackSlotKind::kCreateClosure:
|
|
case FeedbackSlotKind::kLiteral:
|
|
case FeedbackSlotKind::kTypeProfile:
|
|
break;
|
|
case FeedbackSlotKind::kInvalid:
|
|
case FeedbackSlotKind::kKindsNumber:
|
|
UNREACHABLE();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void JSValue::JSValuePrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSValue");
|
|
os << "\n - value: " << Brief(value());
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
|
|
void JSMessageObject::JSMessageObjectPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSMessageObject");
|
|
os << "\n - type: " << type();
|
|
os << "\n - arguments: " << Brief(argument());
|
|
os << "\n - start_position: " << start_position();
|
|
os << "\n - end_position: " << end_position();
|
|
os << "\n - script: " << Brief(script());
|
|
os << "\n - stack_frames: " << Brief(stack_frames());
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
|
|
void String::StringPrint(std::ostream& os) { // NOLINT
|
|
if (!HasOnlyOneByteChars()) {
|
|
os << "u";
|
|
}
|
|
if (StringShape(this).IsInternalized()) {
|
|
os << "#";
|
|
} else if (StringShape(this).IsCons()) {
|
|
os << "c\"";
|
|
} else if (StringShape(this).IsThin()) {
|
|
os << ">\"";
|
|
} else {
|
|
os << "\"";
|
|
}
|
|
|
|
const char truncated_epilogue[] = "...<truncated>";
|
|
int len = length();
|
|
if (!FLAG_use_verbose_printer) {
|
|
if (len > 100) {
|
|
len = 100 - sizeof(truncated_epilogue);
|
|
}
|
|
}
|
|
for (int i = 0; i < len; i++) {
|
|
os << AsUC16(Get(i));
|
|
}
|
|
if (len != length()) {
|
|
os << truncated_epilogue;
|
|
}
|
|
|
|
if (!StringShape(this).IsInternalized()) os << "\"";
|
|
}
|
|
|
|
|
|
void Name::NamePrint(std::ostream& os) { // NOLINT
|
|
if (IsString()) {
|
|
String::cast(this)->StringPrint(os);
|
|
} else {
|
|
os << Brief(this);
|
|
}
|
|
}
|
|
|
|
|
|
static const char* const weekdays[] = {
|
|
"???", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
|
};
|
|
|
|
|
|
void JSDate::JSDatePrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSDate");
|
|
os << "\n - value: " << Brief(value());
|
|
if (!year()->IsSmi()) {
|
|
os << "\n - time = NaN\n";
|
|
} else {
|
|
// TODO(svenpanne) Add some basic formatting to our streams.
|
|
ScopedVector<char> buf(100);
|
|
SNPrintF(buf, "\n - time = %s %04d/%02d/%02d %02d:%02d:%02d\n",
|
|
weekdays[weekday()->IsSmi() ? Smi::ToInt(weekday()) + 1 : 0],
|
|
year()->IsSmi() ? Smi::ToInt(year()) : -1,
|
|
month()->IsSmi() ? Smi::ToInt(month()) : -1,
|
|
day()->IsSmi() ? Smi::ToInt(day()) : -1,
|
|
hour()->IsSmi() ? Smi::ToInt(hour()) : -1,
|
|
min()->IsSmi() ? Smi::ToInt(min()) : -1,
|
|
sec()->IsSmi() ? Smi::ToInt(sec()) : -1);
|
|
os << buf.start();
|
|
}
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
|
|
void JSProxy::JSProxyPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "JSProxy");
|
|
os << "\n - target: ";
|
|
target()->ShortPrint(os);
|
|
os << "\n - handler: ";
|
|
handler()->ShortPrint(os);
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void JSSet::JSSetPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSSet");
|
|
os << " - table: " << Brief(table());
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
|
|
void JSMap::JSMapPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSMap");
|
|
os << " - table: " << Brief(table());
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
void JSCollectionIterator::JSCollectionIteratorPrint(
|
|
std::ostream& os) { // NOLINT
|
|
os << "\n - table: " << Brief(table());
|
|
os << "\n - index: " << Brief(index());
|
|
os << "\n";
|
|
}
|
|
|
|
void JSSetIterator::JSSetIteratorPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSSetIterator");
|
|
JSCollectionIteratorPrint(os);
|
|
}
|
|
|
|
|
|
void JSMapIterator::JSMapIteratorPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSMapIterator");
|
|
JSCollectionIteratorPrint(os);
|
|
}
|
|
|
|
|
|
void JSWeakMap::JSWeakMapPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSWeakMap");
|
|
os << "\n - table: " << Brief(table());
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
|
|
void JSWeakSet::JSWeakSetPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSWeakSet");
|
|
os << "\n - table: " << Brief(table());
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
|
|
void JSArrayBuffer::JSArrayBufferPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSArrayBuffer");
|
|
os << "\n - backing_store: " << backing_store();
|
|
os << "\n - byte_length: " << Brief(byte_length());
|
|
if (is_external()) os << "\n - external";
|
|
if (is_neuterable()) os << "\n - neuterable";
|
|
if (was_neutered()) os << "\n - neutered";
|
|
if (is_shared()) os << "\n - shared";
|
|
if (is_wasm_memory()) os << "\n - is_wasm_memory";
|
|
if (is_growable()) os << "\n - growable";
|
|
JSObjectPrintBody(os, this, !was_neutered());
|
|
}
|
|
|
|
|
|
void JSTypedArray::JSTypedArrayPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSTypedArray");
|
|
os << "\n - buffer: " << Brief(buffer());
|
|
os << "\n - byte_offset: " << Brief(byte_offset());
|
|
os << "\n - byte_length: " << Brief(byte_length());
|
|
os << "\n - length: " << Brief(length());
|
|
if (WasNeutered()) os << "\n - neutered";
|
|
JSObjectPrintBody(os, this, !WasNeutered());
|
|
}
|
|
|
|
void JSArrayIterator::JSArrayIteratorPrint(std::ostream& os) { // NOLING
|
|
JSObjectPrintHeader(os, this, "JSArrayIterator");
|
|
os << "\n - iterated_object: " << Brief(iterated_object());
|
|
os << "\n - next_index: " << Brief(next_index());
|
|
os << "\n - kind: " << kind();
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
void JSDataView::JSDataViewPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSDataView");
|
|
os << "\n - buffer =" << Brief(buffer());
|
|
os << "\n - byte_offset: " << Brief(byte_offset());
|
|
os << "\n - byte_length: " << Brief(byte_length());
|
|
if (WasNeutered()) os << "\n - neutered";
|
|
JSObjectPrintBody(os, this, !WasNeutered());
|
|
}
|
|
|
|
|
|
void JSBoundFunction::JSBoundFunctionPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSBoundFunction");
|
|
os << "\n - bound_target_function: " << Brief(bound_target_function());
|
|
os << "\n - bound_this: " << Brief(bound_this());
|
|
os << "\n - bound_arguments: " << Brief(bound_arguments());
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
void JSFunction::JSFunctionPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "Function");
|
|
os << "\n - function prototype: ";
|
|
if (has_prototype_slot()) {
|
|
if (has_prototype()) {
|
|
os << Brief(prototype());
|
|
if (map()->has_non_instance_prototype()) {
|
|
os << " (non-instance prototype)";
|
|
}
|
|
}
|
|
os << "\n - initial_map: ";
|
|
if (has_initial_map()) os << Brief(initial_map());
|
|
} else {
|
|
os << "<no-prototype-slot>";
|
|
}
|
|
os << "\n - shared_info: " << Brief(shared());
|
|
os << "\n - name: " << Brief(shared()->Name());
|
|
|
|
// Print Builtin name for builtin functions
|
|
int builtin_index = code()->builtin_index();
|
|
if (builtin_index != -1 && !IsInterpreted()) {
|
|
if (builtin_index == Builtins::kDeserializeLazy) {
|
|
if (shared()->HasBuiltinId()) {
|
|
builtin_index = shared()->builtin_id();
|
|
os << "\n - builtin: " << GetIsolate()->builtins()->name(builtin_index)
|
|
<< "(lazy)";
|
|
}
|
|
} else {
|
|
os << "\n - builtin: " << GetIsolate()->builtins()->name(builtin_index);
|
|
}
|
|
}
|
|
|
|
os << "\n - formal_parameter_count: "
|
|
<< shared()->internal_formal_parameter_count();
|
|
os << "\n - kind: " << shared()->kind();
|
|
os << "\n - context: " << Brief(context());
|
|
os << "\n - code: " << Brief(code());
|
|
if (IsInterpreted()) {
|
|
os << "\n - interpreted";
|
|
if (shared()->HasBytecodeArray()) {
|
|
os << "\n - bytecode: " << shared()->GetBytecodeArray();
|
|
}
|
|
}
|
|
if (WasmExportedFunction::IsWasmExportedFunction(this)) {
|
|
WasmExportedFunction* function = WasmExportedFunction::cast(this);
|
|
os << "\n - WASM instance "
|
|
<< reinterpret_cast<void*>(function->instance());
|
|
os << "\n - WASM function index " << function->function_index();
|
|
}
|
|
shared()->PrintSourceCode(os);
|
|
JSObjectPrintBody(os, this);
|
|
os << "\n - feedback vector: ";
|
|
if (has_feedback_vector()) {
|
|
feedback_vector()->FeedbackVectorPrint(os);
|
|
} else {
|
|
os << "not available\n";
|
|
}
|
|
}
|
|
|
|
void SharedFunctionInfo::PrintSourceCode(std::ostream& os) {
|
|
if (HasSourceCode()) {
|
|
os << "\n - source code: ";
|
|
String* source = String::cast(Script::cast(script())->source());
|
|
int start = StartPosition();
|
|
int length = EndPosition() - start;
|
|
std::unique_ptr<char[]> source_string = source->ToCString(
|
|
DISALLOW_NULLS, FAST_STRING_TRAVERSAL, start, length, nullptr);
|
|
os << source_string.get();
|
|
}
|
|
}
|
|
|
|
void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "SharedFunctionInfo");
|
|
os << "\n - name: ";
|
|
if (HasSharedName()) {
|
|
os << Brief(Name());
|
|
} else {
|
|
os << "<no-shared-name>";
|
|
}
|
|
if (HasInferredName()) {
|
|
os << "\n - inferred name: " << Brief(inferred_name());
|
|
}
|
|
os << "\n - kind: " << kind();
|
|
if (needs_home_object()) {
|
|
os << "\n - needs_home_object";
|
|
}
|
|
os << "\n - function_map_index: " << function_map_index();
|
|
os << "\n - formal_parameter_count: " << internal_formal_parameter_count();
|
|
os << "\n - expected_nof_properties: " << expected_nof_properties();
|
|
os << "\n - language_mode: " << language_mode();
|
|
os << "\n - data: " << Brief(function_data());
|
|
os << "\n - code (from data): " << Brief(GetCode());
|
|
PrintSourceCode(os);
|
|
// Script files are often large, hard to read.
|
|
// os << "\n - script =";
|
|
// script()->Print(os);
|
|
if (is_named_expression()) {
|
|
os << "\n - named expression";
|
|
} else if (is_anonymous_expression()) {
|
|
os << "\n - anonymous expression";
|
|
} else if (is_declaration()) {
|
|
os << "\n - declaration";
|
|
}
|
|
os << "\n - function token position: " << function_token_position();
|
|
os << "\n - start position: " << StartPosition();
|
|
os << "\n - end position: " << EndPosition();
|
|
if (HasDebugInfo()) {
|
|
os << "\n - debug info: " << Brief(debug_info());
|
|
} else {
|
|
os << "\n - no debug info";
|
|
}
|
|
os << "\n - scope info: " << Brief(scope_info());
|
|
if (HasOuterScopeInfo()) {
|
|
os << "\n - outer scope info: " << Brief(GetOuterScopeInfo());
|
|
}
|
|
os << "\n - length: " << length();
|
|
os << "\n - feedback_metadata: ";
|
|
if (HasFeedbackMetadata()) {
|
|
feedback_metadata()->FeedbackMetadataPrint(os);
|
|
} else {
|
|
os << "<none>";
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void JSGlobalProxy::JSGlobalProxyPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSGlobalProxy");
|
|
if (!GetIsolate()->bootstrapper()->IsActive()) {
|
|
os << "\n - native context: " << Brief(native_context());
|
|
}
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
|
|
void JSGlobalObject::JSGlobalObjectPrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSGlobalObject");
|
|
if (!GetIsolate()->bootstrapper()->IsActive()) {
|
|
os << "\n - native context: " << Brief(native_context());
|
|
}
|
|
os << "\n - global proxy: " << Brief(global_proxy());
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
|
|
void Cell::CellPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "Cell");
|
|
os << "\n - value: " << Brief(value());
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void PropertyCell::PropertyCellPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "PropertyCell");
|
|
os << "\n - name: ";
|
|
name()->NamePrint(os);
|
|
os << "\n - value: " << Brief(value());
|
|
os << "\n - details: ";
|
|
property_details().PrintAsSlowTo(os);
|
|
PropertyCellType cell_type = property_details().cell_type();
|
|
os << "\n - cell_type: ";
|
|
if (value()->IsTheHole(GetIsolate())) {
|
|
switch (cell_type) {
|
|
case PropertyCellType::kUninitialized:
|
|
os << "Uninitialized";
|
|
break;
|
|
case PropertyCellType::kInvalidated:
|
|
os << "Invalidated";
|
|
break;
|
|
default:
|
|
os << "??? " << static_cast<int>(cell_type);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (cell_type) {
|
|
case PropertyCellType::kUndefined:
|
|
os << "Undefined";
|
|
break;
|
|
case PropertyCellType::kConstant:
|
|
os << "Constant";
|
|
break;
|
|
case PropertyCellType::kConstantType:
|
|
os << "ConstantType"
|
|
<< " (";
|
|
switch (GetConstantType()) {
|
|
case PropertyCellConstantType::kSmi:
|
|
os << "Smi";
|
|
break;
|
|
case PropertyCellConstantType::kStableMap:
|
|
os << "StableMap";
|
|
break;
|
|
}
|
|
os << ")";
|
|
break;
|
|
case PropertyCellType::kMutable:
|
|
os << "Mutable";
|
|
break;
|
|
}
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void WeakCell::WeakCellPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "WeakCell");
|
|
if (cleared()) {
|
|
os << "\n - cleared";
|
|
} else {
|
|
os << "\n - value: " << Brief(value());
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void Code::CodePrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "Code");
|
|
os << "\n";
|
|
#ifdef ENABLE_DISASSEMBLER
|
|
if (FLAG_use_verbose_printer) {
|
|
Disassemble(nullptr, os);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CodeDataContainer::CodeDataContainerPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "CodeDataContainer");
|
|
os << "\n - kind_specific_flags: " << kind_specific_flags();
|
|
os << "\n";
|
|
}
|
|
|
|
void Foreign::ForeignPrint(std::ostream& os) { // NOLINT
|
|
os << "foreign address : " << reinterpret_cast<void*>(foreign_address());
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void AccessorInfo::AccessorInfoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "AccessorInfo");
|
|
os << "\n - name: " << Brief(name());
|
|
os << "\n - flags: " << flags();
|
|
os << "\n - getter: " << Brief(getter());
|
|
os << "\n - setter: " << Brief(setter());
|
|
os << "\n - js_getter: " << Brief(js_getter());
|
|
os << "\n - data: " << Brief(data());
|
|
os << "\n";
|
|
}
|
|
|
|
void CallbackTask::CallbackTaskPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "CallbackTask");
|
|
os << "\n - callback: " << Brief(callback());
|
|
os << "\n - data: " << Brief(data());
|
|
os << "\n";
|
|
}
|
|
|
|
void CallableTask::CallableTaskPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "CallableTask");
|
|
os << "\n - context: " << Brief(context());
|
|
os << "\n - callable: " << Brief(callable());
|
|
os << "\n";
|
|
}
|
|
|
|
void PromiseFulfillReactionJobTask::PromiseFulfillReactionJobTaskPrint(
|
|
std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "PromiseFulfillReactionJobTask");
|
|
os << "\n - argument: " << Brief(argument());
|
|
os << "\n - context: " << Brief(context());
|
|
os << "\n - handler: " << Brief(handler());
|
|
os << "\n - payload: " << Brief(payload());
|
|
os << "\n";
|
|
}
|
|
|
|
void PromiseRejectReactionJobTask::PromiseRejectReactionJobTaskPrint(
|
|
std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "PromiseRejectReactionJobTask");
|
|
os << "\n - argument: " << Brief(argument());
|
|
os << "\n - context: " << Brief(context());
|
|
os << "\n - handler: " << Brief(handler());
|
|
os << "\n - payload: " << Brief(payload());
|
|
os << "\n";
|
|
}
|
|
|
|
void PromiseResolveThenableJobTask::PromiseResolveThenableJobTaskPrint(
|
|
std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "PromiseResolveThenableJobTask");
|
|
os << "\n - context: " << Brief(context());
|
|
os << "\n - promise_to_resolve: " << Brief(promise_to_resolve());
|
|
os << "\n - then: " << Brief(then());
|
|
os << "\n - thenable: " << Brief(thenable());
|
|
os << "\n";
|
|
}
|
|
|
|
void PromiseCapability::PromiseCapabilityPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "PromiseCapability");
|
|
os << "\n - promise: " << Brief(promise());
|
|
os << "\n - resolve: " << Brief(resolve());
|
|
os << "\n - reject: " << Brief(reject());
|
|
os << "\n";
|
|
}
|
|
|
|
void PromiseReaction::PromiseReactionPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "PromiseReaction");
|
|
os << "\n - next: " << Brief(next());
|
|
os << "\n - reject_handler: " << Brief(reject_handler());
|
|
os << "\n - fulfill_handler: " << Brief(fulfill_handler());
|
|
os << "\n - payload: " << Brief(payload());
|
|
os << "\n";
|
|
}
|
|
|
|
void AsyncGeneratorRequest::AsyncGeneratorRequestPrint(
|
|
std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "AsyncGeneratorRequest");
|
|
const char* mode = "Invalid!";
|
|
switch (resume_mode()) {
|
|
case JSGeneratorObject::kNext:
|
|
mode = ".next()";
|
|
break;
|
|
case JSGeneratorObject::kReturn:
|
|
mode = ".return()";
|
|
break;
|
|
case JSGeneratorObject::kThrow:
|
|
mode = ".throw()";
|
|
break;
|
|
}
|
|
os << "\n - resume mode: " << mode;
|
|
os << "\n - value: " << Brief(value());
|
|
os << "\n - next: " << Brief(next());
|
|
os << "\n";
|
|
}
|
|
|
|
void ModuleInfoEntry::ModuleInfoEntryPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "ModuleInfoEntry");
|
|
os << "\n - export_name: " << Brief(export_name());
|
|
os << "\n - local_name: " << Brief(local_name());
|
|
os << "\n - import_name: " << Brief(import_name());
|
|
os << "\n - module_request: " << module_request();
|
|
os << "\n - cell_index: " << cell_index();
|
|
os << "\n - beg_pos: " << beg_pos();
|
|
os << "\n - end_pos: " << end_pos();
|
|
os << "\n";
|
|
}
|
|
|
|
void Module::ModulePrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "Module");
|
|
os << "\n - origin: " << Brief(script()->GetNameOrSourceURL());
|
|
os << "\n - code: " << Brief(code());
|
|
os << "\n - exports: " << Brief(exports());
|
|
os << "\n - requested_modules: " << Brief(requested_modules());
|
|
os << "\n - script: " << Brief(script());
|
|
os << "\n - import_meta: " << Brief(import_meta());
|
|
os << "\n - status: " << status();
|
|
os << "\n - exception: " << Brief(exception());
|
|
os << "\n";
|
|
}
|
|
|
|
void JSModuleNamespace::JSModuleNamespacePrint(std::ostream& os) { // NOLINT
|
|
JSObjectPrintHeader(os, this, "JSModuleNamespace");
|
|
os << "\n - module: " << Brief(module());
|
|
JSObjectPrintBody(os, this);
|
|
}
|
|
|
|
void PrototypeInfo::PrototypeInfoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "PrototypeInfo");
|
|
os << "\n - weak cell: " << Brief(weak_cell());
|
|
os << "\n - prototype users: " << Brief(prototype_users());
|
|
os << "\n - registry slot: " << registry_slot();
|
|
os << "\n - object create map: " << Brief(object_create_map());
|
|
os << "\n - should_be_fast_map: " << should_be_fast_map();
|
|
os << "\n";
|
|
}
|
|
|
|
void Tuple2::Tuple2Print(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "Tuple2");
|
|
os << "\n - value1: " << Brief(value1());
|
|
os << "\n - value2: " << Brief(value2());
|
|
os << "\n";
|
|
}
|
|
|
|
void Tuple3::Tuple3Print(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "Tuple3");
|
|
os << "\n - value1: " << Brief(value1());
|
|
os << "\n - value2: " << Brief(value2());
|
|
os << "\n - value3: " << Brief(value3());
|
|
os << "\n";
|
|
}
|
|
|
|
void WasmCompiledModule::WasmCompiledModulePrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "WasmCompiledModule");
|
|
os << "\n - shared: " << Brief(shared());
|
|
os << "\n";
|
|
}
|
|
|
|
void WasmDebugInfo::WasmDebugInfoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "WasmDebugInfo");
|
|
os << "\n - wasm_instance: " << Brief(wasm_instance());
|
|
os << "\n";
|
|
}
|
|
|
|
void WasmSharedModuleData::WasmSharedModuleDataPrint(
|
|
std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "WasmSharedModuleData");
|
|
os << "\n - module: " << module();
|
|
os << "\n";
|
|
}
|
|
|
|
void LoadHandler::LoadHandlerPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "LoadHandler");
|
|
// TODO(ishell): implement printing based on handler kind
|
|
os << "\n - handler: " << Brief(smi_handler());
|
|
os << "\n - validity_cell: " << Brief(validity_cell());
|
|
int data_count = data_field_count();
|
|
if (data_count >= 1) {
|
|
os << "\n - data1: " << Brief(data1());
|
|
}
|
|
if (data_count >= 2) {
|
|
os << "\n - data2: " << Brief(data2());
|
|
}
|
|
if (data_count >= 3) {
|
|
os << "\n - data3: " << Brief(data3());
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
void StoreHandler::StoreHandlerPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "StoreHandler");
|
|
// TODO(ishell): implement printing based on handler kind
|
|
os << "\n - handler: " << Brief(smi_handler());
|
|
os << "\n - validity_cell: " << Brief(validity_cell());
|
|
int data_count = data_field_count();
|
|
if (data_count >= 1) {
|
|
os << "\n - data1: " << Brief(data1());
|
|
}
|
|
if (data_count >= 2) {
|
|
os << "\n - data2: " << Brief(data2());
|
|
}
|
|
if (data_count >= 3) {
|
|
os << "\n - data3: " << Brief(data3());
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
void ContextExtension::ContextExtensionPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "ContextExtension");
|
|
os << "\n - scope_info: " << Brief(scope_info());
|
|
os << "\n - extension: " << Brief(extension());
|
|
os << "\n";
|
|
}
|
|
|
|
void AccessorPair::AccessorPairPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "AccessorPair");
|
|
os << "\n - getter: " << Brief(getter());
|
|
os << "\n - setter: " << Brief(setter());
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void AccessCheckInfo::AccessCheckInfoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "AccessCheckInfo");
|
|
os << "\n - callback: " << Brief(callback());
|
|
os << "\n - named_interceptor: " << Brief(named_interceptor());
|
|
os << "\n - indexed_interceptor: " << Brief(indexed_interceptor());
|
|
os << "\n - data: " << Brief(data());
|
|
os << "\n";
|
|
}
|
|
|
|
void CallHandlerInfo::CallHandlerInfoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "CallHandlerInfo");
|
|
os << "\n - callback: " << Brief(callback());
|
|
os << "\n - js_callback: " << Brief(js_callback());
|
|
os << "\n - data: " << Brief(data());
|
|
os << "\n - side_effect_free: "
|
|
<< (IsSideEffectFreeCallHandlerInfo() ? "true" : "false");
|
|
os << "\n";
|
|
}
|
|
|
|
void InterceptorInfo::InterceptorInfoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "InterceptorInfo");
|
|
os << "\n - getter: " << Brief(getter());
|
|
os << "\n - setter: " << Brief(setter());
|
|
os << "\n - query: " << Brief(query());
|
|
os << "\n - deleter: " << Brief(deleter());
|
|
os << "\n - enumerator: " << Brief(enumerator());
|
|
os << "\n - data: " << Brief(data());
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void FunctionTemplateInfo::FunctionTemplateInfoPrint(
|
|
std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "FunctionTemplateInfo");
|
|
os << "\n - class name: " << Brief(class_name());
|
|
os << "\n - tag: " << Brief(tag());
|
|
os << "\n - serial_number: " << Brief(serial_number());
|
|
os << "\n - property_list: " << Brief(property_list());
|
|
os << "\n - call_code: " << Brief(call_code());
|
|
os << "\n - property_accessors: " << Brief(property_accessors());
|
|
os << "\n - prototype_template: " << Brief(prototype_template());
|
|
os << "\n - parent_template: " << Brief(parent_template());
|
|
os << "\n - named_property_handler: " << Brief(named_property_handler());
|
|
os << "\n - indexed_property_handler: " << Brief(indexed_property_handler());
|
|
os << "\n - instance_template: " << Brief(instance_template());
|
|
os << "\n - signature: " << Brief(signature());
|
|
os << "\n - access_check_info: " << Brief(access_check_info());
|
|
os << "\n - cached_property_name: " << Brief(cached_property_name());
|
|
os << "\n - hidden_prototype: " << (hidden_prototype() ? "true" : "false");
|
|
os << "\n - undetectable: " << (undetectable() ? "true" : "false");
|
|
os << "\n - need_access_check: " << (needs_access_check() ? "true" : "false");
|
|
os << "\n - instantiated: " << (instantiated() ? "true" : "false");
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void ObjectTemplateInfo::ObjectTemplateInfoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "ObjectTemplateInfo");
|
|
os << "\n - tag: " << Brief(tag());
|
|
os << "\n - serial_number: " << Brief(serial_number());
|
|
os << "\n - property_list: " << Brief(property_list());
|
|
os << "\n - property_accessors: " << Brief(property_accessors());
|
|
os << "\n - constructor: " << Brief(constructor());
|
|
os << "\n - embedder_field_count: " << embedder_field_count();
|
|
os << "\n - immutable_proto: " << (immutable_proto() ? "true" : "false");
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void AllocationSite::AllocationSitePrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "AllocationSite");
|
|
os << "\n - weak_next: " << Brief(weak_next());
|
|
os << "\n - dependent code: " << Brief(dependent_code());
|
|
os << "\n - nested site: " << Brief(nested_site());
|
|
os << "\n - memento found count: "
|
|
<< Brief(Smi::FromInt(memento_found_count()));
|
|
os << "\n - memento create count: "
|
|
<< Brief(Smi::FromInt(memento_create_count()));
|
|
os << "\n - pretenure decision: "
|
|
<< Brief(Smi::FromInt(pretenure_decision()));
|
|
os << "\n - transition_info: ";
|
|
if (!PointsToLiteral()) {
|
|
ElementsKind kind = GetElementsKind();
|
|
os << "Array allocation with ElementsKind " << ElementsKindToString(kind);
|
|
} else if (boilerplate()->IsJSArray()) {
|
|
os << "Array literal with boilerplate " << Brief(boilerplate());
|
|
} else {
|
|
os << "Object literal with boilerplate " << Brief(boilerplate());
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
|
|
void AllocationMemento::AllocationMementoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "AllocationMemento");
|
|
os << "\n - allocation site: ";
|
|
if (IsValid()) {
|
|
GetAllocationSite()->Print(os);
|
|
} else {
|
|
os << "<invalid>\n";
|
|
}
|
|
}
|
|
|
|
|
|
void Script::ScriptPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "Script");
|
|
os << "\n - source: " << Brief(source());
|
|
os << "\n - name: " << Brief(name());
|
|
os << "\n - line_offset: " << line_offset();
|
|
os << "\n - column_offset: " << column_offset();
|
|
os << "\n - type: " << type();
|
|
os << "\n - id: " << id();
|
|
os << "\n - context data: " << Brief(context_data());
|
|
os << "\n - wrapper: " << Brief(wrapper());
|
|
os << "\n - compilation type: " << compilation_type();
|
|
os << "\n - line ends: " << Brief(line_ends());
|
|
if (has_eval_from_shared()) {
|
|
os << "\n - eval from shared: " << Brief(eval_from_shared());
|
|
}
|
|
if (is_wrapped()) {
|
|
os << "\n - wrapped arguments: " << Brief(wrapped_arguments());
|
|
}
|
|
os << "\n - eval from position: " << eval_from_position();
|
|
os << "\n - shared function infos: " << Brief(shared_function_infos());
|
|
os << "\n";
|
|
}
|
|
|
|
namespace {
|
|
void PrintScopeInfoList(ScopeInfo* scope_info, std::ostream& os,
|
|
const char* list_name, int nof_internal_slots,
|
|
int start, int length) {
|
|
if (length <= 0) return;
|
|
int end = start + length;
|
|
os << "\n - " << list_name;
|
|
if (nof_internal_slots > 0) {
|
|
os << " " << start << "-" << end << " [internal slots]";
|
|
}
|
|
os << " {\n";
|
|
for (int i = nof_internal_slots; start < end; ++i, ++start) {
|
|
os << " - " << i << ": ";
|
|
String::cast(scope_info->get(start))->ShortPrint(os);
|
|
os << "\n";
|
|
}
|
|
os << " }";
|
|
}
|
|
} // namespace
|
|
|
|
void ScopeInfo::ScopeInfoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "ScopeInfo");
|
|
if (length() == 0) {
|
|
os << "\n - length = 0\n";
|
|
return;
|
|
}
|
|
|
|
os << "\n - scope type: " << scope_type();
|
|
os << "\n - language mode: " << language_mode();
|
|
os << "\n - local count: " << LocalCount();
|
|
os << "\n - stack slot count: " << StackSlotCount();
|
|
if (HasReceiver()) os << "\n - has receiver";
|
|
if (HasNewTarget()) os << "\n - needs new target";
|
|
if (HasOuterScopeInfo()) {
|
|
os << "\n - outer scope info: " << Brief(OuterScopeInfo());
|
|
}
|
|
if (HasFunctionName()) {
|
|
os << "\n - function name: " << Brief(FunctionName());
|
|
}
|
|
if (HasInferredFunctionName()) {
|
|
os << "\n - inferred function name: " << Brief(InferredFunctionName());
|
|
}
|
|
|
|
if (HasPositionInfo()) {
|
|
os << "\n - start position: " << StartPosition();
|
|
os << "\n - end position: " << EndPosition();
|
|
}
|
|
os << "\n - length: " << length();
|
|
if (length() > 0) {
|
|
PrintScopeInfoList(this, os, "parameters", 0, ParameterNamesIndex(),
|
|
ParameterCount());
|
|
PrintScopeInfoList(this, os, "stack slots", 0, StackLocalNamesIndex(),
|
|
StackLocalCount());
|
|
PrintScopeInfoList(this, os, "context slots", Context::MIN_CONTEXT_SLOTS,
|
|
ContextLocalNamesIndex(), ContextLocalCount());
|
|
// TODO(neis): Print module stuff if present.
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
void DebugInfo::DebugInfoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "DebugInfo");
|
|
os << "\n - flags: " << flags();
|
|
os << "\n - debugger_hints: " << debugger_hints();
|
|
os << "\n - shared: " << Brief(shared());
|
|
os << "\n - debug bytecode array: " << Brief(debug_bytecode_array());
|
|
os << "\n - break_points: ";
|
|
break_points()->Print(os);
|
|
os << "\n - coverage_info: " << Brief(coverage_info());
|
|
}
|
|
|
|
|
|
void StackFrameInfo::StackFrameInfoPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "StackFrame");
|
|
os << "\n - line_number: " << line_number();
|
|
os << "\n - column_number: " << column_number();
|
|
os << "\n - script_id: " << script_id();
|
|
os << "\n - script_name: " << Brief(script_name());
|
|
os << "\n - script_name_or_source_url: "
|
|
<< Brief(script_name_or_source_url());
|
|
os << "\n - function_name: " << Brief(function_name());
|
|
os << "\n - is_eval: " << (is_eval() ? "true" : "false");
|
|
os << "\n - is_constructor: " << (is_constructor() ? "true" : "false");
|
|
os << "\n";
|
|
}
|
|
|
|
static void PrintBitMask(std::ostream& os, uint32_t value) { // NOLINT
|
|
for (int i = 0; i < 32; i++) {
|
|
if ((i & 7) == 0) os << " ";
|
|
os << (((value & 1) == 0) ? "_" : "x");
|
|
value >>= 1;
|
|
}
|
|
}
|
|
|
|
|
|
void LayoutDescriptor::Print() {
|
|
OFStream os(stdout);
|
|
this->Print(os);
|
|
os << std::flush;
|
|
}
|
|
|
|
void LayoutDescriptor::ShortPrint(std::ostream& os) {
|
|
if (IsSmi()) {
|
|
os << this; // Print tagged value for easy use with "jld" gdb macro.
|
|
} else {
|
|
os << Brief(this);
|
|
}
|
|
}
|
|
|
|
void LayoutDescriptor::Print(std::ostream& os) { // NOLINT
|
|
os << "Layout descriptor: ";
|
|
if (IsFastPointerLayout()) {
|
|
os << "<all tagged>";
|
|
} else if (IsSmi()) {
|
|
os << "fast";
|
|
PrintBitMask(os, static_cast<uint32_t>(Smi::ToInt(this)));
|
|
} else if (IsOddball() &&
|
|
IsUninitialized(HeapObject::cast(this)->GetIsolate())) {
|
|
os << "<uninitialized>";
|
|
} else {
|
|
os << "slow";
|
|
int num_words = number_of_layout_words();
|
|
for (int i = 0; i < num_words; i++) {
|
|
if (i > 0) os << " |";
|
|
PrintBitMask(os, get_layout_word(i));
|
|
}
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
void PreParsedScopeData::PreParsedScopeDataPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "PreParsedScopeData");
|
|
os << "\n - scope_data: " << Brief(scope_data());
|
|
os << "\n - child_data: " << Brief(child_data());
|
|
os << "\n";
|
|
}
|
|
|
|
void InterpreterData::InterpreterDataPrint(std::ostream& os) { // NOLINT
|
|
HeapObject::PrintHeader(os, "InterpreterData");
|
|
os << "\n - bytecode_array: " << Brief(bytecode_array());
|
|
os << "\n - interpreter_trampoline: " << Brief(interpreter_trampoline());
|
|
os << "\n";
|
|
}
|
|
|
|
#endif // OBJECT_PRINT
|
|
|
|
// TODO(cbruni): remove once the new maptracer is in place.
|
|
void Name::NameShortPrint() {
|
|
if (this->IsString()) {
|
|
PrintF("%s", String::cast(this)->ToCString().get());
|
|
} else {
|
|
DCHECK(this->IsSymbol());
|
|
Symbol* s = Symbol::cast(this);
|
|
if (s->name()->IsUndefined(GetIsolate())) {
|
|
PrintF("#<%s>", s->PrivateSymbolToName());
|
|
} else {
|
|
PrintF("<%s>", String::cast(s->name())->ToCString().get());
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO(cbruni): remove once the new maptracer is in place.
|
|
int Name::NameShortPrint(Vector<char> str) {
|
|
if (this->IsString()) {
|
|
return SNPrintF(str, "%s", String::cast(this)->ToCString().get());
|
|
} else {
|
|
DCHECK(this->IsSymbol());
|
|
Symbol* s = Symbol::cast(this);
|
|
if (s->name()->IsUndefined(GetIsolate())) {
|
|
return SNPrintF(str, "#<%s>", s->PrivateSymbolToName());
|
|
} else {
|
|
return SNPrintF(str, "<%s>", String::cast(s->name())->ToCString().get());
|
|
}
|
|
}
|
|
}
|
|
|
|
void Map::PrintMapDetails(std::ostream& os, JSObject* holder) {
|
|
DisallowHeapAllocation no_gc;
|
|
#ifdef OBJECT_PRINT
|
|
this->MapPrint(os);
|
|
#else
|
|
os << "Map=" << reinterpret_cast<void*>(this);
|
|
#endif
|
|
os << "\n";
|
|
instance_descriptors()->PrintDescriptors(os);
|
|
if (is_dictionary_map() && holder != nullptr) {
|
|
os << holder->property_dictionary() << "\n";
|
|
}
|
|
}
|
|
|
|
void DescriptorArray::PrintDescriptors(std::ostream& os) { // NOLINT
|
|
HandleScope scope(GetIsolate());
|
|
os << "Descriptor array #" << number_of_descriptors() << ":";
|
|
for (int i = 0; i < number_of_descriptors(); i++) {
|
|
Name* key = GetKey(i);
|
|
os << "\n [" << i << "]: ";
|
|
#ifdef OBJECT_PRINT
|
|
key->NamePrint(os);
|
|
#else
|
|
key->ShortPrint(os);
|
|
#endif
|
|
os << " ";
|
|
PrintDescriptorDetails(os, i, PropertyDetails::kPrintFull);
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
void DescriptorArray::PrintDescriptorDetails(std::ostream& os, int descriptor,
|
|
PropertyDetails::PrintMode mode) {
|
|
PropertyDetails details = GetDetails(descriptor);
|
|
details.PrintAsFastTo(os, mode);
|
|
os << " @ ";
|
|
Object* value = GetValue(descriptor);
|
|
switch (details.location()) {
|
|
case kField: {
|
|
FieldType* field_type = Map::UnwrapFieldType(value);
|
|
field_type->PrintTo(os);
|
|
break;
|
|
}
|
|
case kDescriptor:
|
|
os << Brief(value);
|
|
if (value->IsAccessorPair()) {
|
|
AccessorPair* pair = AccessorPair::cast(value);
|
|
os << "(get: " << Brief(pair->getter())
|
|
<< ", set: " << Brief(pair->setter()) << ")";
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if defined(DEBUG) || defined(OBJECT_PRINT)
|
|
// This method is only meant to be called from gdb for debugging purposes.
|
|
// Since the string can also be in two-byte encoding, non-Latin1 characters
|
|
// will be ignored in the output.
|
|
char* String::ToAsciiArray() {
|
|
// Static so that subsequent calls frees previously allocated space.
|
|
// This also means that previous results will be overwritten.
|
|
static char* buffer = nullptr;
|
|
if (buffer != nullptr) delete[] buffer;
|
|
buffer = new char[length() + 1];
|
|
WriteToFlat(this, reinterpret_cast<uint8_t*>(buffer), 0, length());
|
|
buffer[length()] = 0;
|
|
return buffer;
|
|
}
|
|
|
|
void DescriptorArray::Print() {
|
|
OFStream os(stdout);
|
|
this->PrintDescriptors(os);
|
|
os << std::flush;
|
|
}
|
|
// static
|
|
void TransitionsAccessor::PrintOneTransition(std::ostream& os, Name* key,
|
|
Map* target, Object* raw_target) {
|
|
os << "\n ";
|
|
#ifdef OBJECT_PRINT
|
|
key->NamePrint(os);
|
|
#else
|
|
key->ShortPrint(os);
|
|
#endif
|
|
os << ": ";
|
|
Heap* heap = key->GetHeap();
|
|
if (key == heap->nonextensible_symbol()) {
|
|
os << "(transition to non-extensible)";
|
|
} else if (key == heap->sealed_symbol()) {
|
|
os << "(transition to sealed)";
|
|
} else if (key == heap->frozen_symbol()) {
|
|
os << "(transition to frozen)";
|
|
} else if (key == heap->elements_transition_symbol()) {
|
|
os << "(transition to " << ElementsKindToString(target->elements_kind())
|
|
<< ")";
|
|
} else if (key == heap->strict_function_transition_symbol()) {
|
|
os << " (transition to strict function)";
|
|
} else {
|
|
DCHECK(!IsSpecialTransition(key));
|
|
os << "(transition to ";
|
|
int descriptor = target->LastAdded();
|
|
DescriptorArray* descriptors = target->instance_descriptors();
|
|
descriptors->PrintDescriptorDetails(os, descriptor,
|
|
PropertyDetails::kForTransitions);
|
|
os << ")";
|
|
}
|
|
os << " -> " << Brief(target);
|
|
if (!raw_target->IsMap() && !raw_target->IsWeakCell()) {
|
|
os << " (handler: " << Brief(raw_target) << ")";
|
|
}
|
|
}
|
|
|
|
void TransitionArray::Print() {
|
|
OFStream os(stdout);
|
|
Print(os);
|
|
}
|
|
|
|
// TODO(ishell): unify with TransitionArrayPrint().
|
|
void TransitionArray::Print(std::ostream& os) {
|
|
int num_transitions = number_of_transitions();
|
|
os << "Transition array #" << num_transitions << ":";
|
|
for (int i = 0; i < num_transitions; i++) {
|
|
Name* key = GetKey(i);
|
|
Map* target = GetTarget(i);
|
|
Object* raw_target = GetRawTarget(i);
|
|
TransitionsAccessor::PrintOneTransition(os, key, target, raw_target);
|
|
}
|
|
os << "\n" << std::flush;
|
|
}
|
|
|
|
void TransitionsAccessor::PrintTransitions(std::ostream& os) { // NOLINT
|
|
Map* target;
|
|
switch (encoding()) {
|
|
case kPrototypeInfo:
|
|
case kUninitialized:
|
|
return;
|
|
case kWeakRef:
|
|
target = Map::cast(raw_transitions_->ToWeakHeapObject());
|
|
break;
|
|
case kHandler: {
|
|
WeakCell* cell = GetTargetCell();
|
|
DCHECK(!cell->cleared());
|
|
target = Map::cast(cell->value());
|
|
break;
|
|
}
|
|
case kFullTransitionArray:
|
|
return transitions()->Print(os);
|
|
}
|
|
Name* key = GetSimpleTransitionKey(target);
|
|
PrintOneTransition(os, key, target, raw_transitions_->GetHeapObject());
|
|
}
|
|
|
|
void TransitionsAccessor::PrintTransitionTree() {
|
|
OFStream os(stdout);
|
|
os << "map= " << Brief(map_);
|
|
DisallowHeapAllocation no_gc;
|
|
PrintTransitionTree(os, 0, &no_gc);
|
|
os << "\n" << std::flush;
|
|
}
|
|
|
|
void TransitionsAccessor::PrintTransitionTree(std::ostream& os, int level,
|
|
DisallowHeapAllocation* no_gc) {
|
|
int num_transitions = NumberOfTransitions();
|
|
if (num_transitions == 0) return;
|
|
for (int i = 0; i < num_transitions; i++) {
|
|
Name* key = GetKey(i);
|
|
Map* target = GetTarget(i);
|
|
os << std::endl
|
|
<< " " << level << "/" << i << ":" << std::setw(level * 2 + 2) << " ";
|
|
std::stringstream ss;
|
|
ss << Brief(target);
|
|
os << std::left << std::setw(50) << ss.str() << ": ";
|
|
|
|
Heap* heap = key->GetHeap();
|
|
if (key == heap->nonextensible_symbol()) {
|
|
os << "to non-extensible";
|
|
} else if (key == heap->sealed_symbol()) {
|
|
os << "to sealed ";
|
|
} else if (key == heap->frozen_symbol()) {
|
|
os << "to frozen";
|
|
} else if (key == heap->elements_transition_symbol()) {
|
|
os << "to " << ElementsKindToString(target->elements_kind());
|
|
} else if (key == heap->strict_function_transition_symbol()) {
|
|
os << "to strict function";
|
|
} else {
|
|
#ifdef OBJECT_PRINT
|
|
key->NamePrint(os);
|
|
#else
|
|
key->ShortPrint(os);
|
|
#endif
|
|
os << " ";
|
|
DCHECK(!IsSpecialTransition(key));
|
|
os << "to ";
|
|
int descriptor = target->LastAdded();
|
|
DescriptorArray* descriptors = target->instance_descriptors();
|
|
descriptors->PrintDescriptorDetails(os, descriptor,
|
|
PropertyDetails::kForTransitions);
|
|
}
|
|
TransitionsAccessor transitions(target, no_gc);
|
|
transitions.PrintTransitionTree(os, level + 1, no_gc);
|
|
}
|
|
}
|
|
|
|
void JSObject::PrintTransitions(std::ostream& os) { // NOLINT
|
|
DisallowHeapAllocation no_gc;
|
|
TransitionsAccessor ta(map(), &no_gc);
|
|
if (ta.NumberOfTransitions() == 0) return;
|
|
os << "\n - transitions";
|
|
ta.PrintTransitions(os);
|
|
}
|
|
#endif // defined(DEBUG) || defined(OBJECT_PRINT)
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
//
|
|
// The following functions are used by our gdb macros.
|
|
//
|
|
extern void _v8_internal_Print_Object(void* object) {
|
|
reinterpret_cast<i::Object*>(object)->Print();
|
|
}
|
|
|
|
extern void _v8_internal_Print_Code(void* object) {
|
|
i::Address address = reinterpret_cast<i::Address>(object);
|
|
i::Isolate* isolate = i::Isolate::Current();
|
|
|
|
i::wasm::WasmCode* wasm_code =
|
|
isolate->wasm_engine()->code_manager()->LookupCode(address);
|
|
if (wasm_code) {
|
|
wasm_code->Print(isolate);
|
|
return;
|
|
}
|
|
|
|
if (!isolate->heap()->InSpaceSlow(address, i::CODE_SPACE) &&
|
|
!isolate->heap()->InSpaceSlow(address, i::LO_SPACE)) {
|
|
i::PrintF(
|
|
"%p is not within the current isolate's large object or code spaces\n",
|
|
static_cast<void*>(address));
|
|
return;
|
|
}
|
|
|
|
i::Code* code = isolate->FindCodeObject(address);
|
|
if (!code->IsCode()) {
|
|
i::PrintF("No code object found containing %p\n",
|
|
static_cast<void*>(address));
|
|
return;
|
|
}
|
|
#ifdef ENABLE_DISASSEMBLER
|
|
i::OFStream os(stdout);
|
|
code->Disassemble(nullptr, os, address);
|
|
#else // ENABLE_DISASSEMBLER
|
|
code->Print();
|
|
#endif // ENABLE_DISASSEMBLER
|
|
}
|
|
|
|
extern void _v8_internal_Print_FeedbackMetadata(void* object) {
|
|
if (reinterpret_cast<i::Object*>(object)->IsSmi()) {
|
|
printf("Please provide a feedback metadata object\n");
|
|
} else {
|
|
reinterpret_cast<i::FeedbackMetadata*>(object)->Print();
|
|
}
|
|
}
|
|
|
|
extern void _v8_internal_Print_FeedbackVector(void* object) {
|
|
if (reinterpret_cast<i::Object*>(object)->IsSmi()) {
|
|
printf("Please provide a feedback vector\n");
|
|
} else {
|
|
reinterpret_cast<i::FeedbackVector*>(object)->Print();
|
|
}
|
|
}
|
|
|
|
extern void _v8_internal_Print_DescriptorArray(void* object) {
|
|
if (reinterpret_cast<i::Object*>(object)->IsSmi()) {
|
|
printf("Please provide a descriptor array\n");
|
|
} else {
|
|
reinterpret_cast<i::DescriptorArray*>(object)->Print();
|
|
}
|
|
}
|
|
|
|
extern void _v8_internal_Print_LayoutDescriptor(void* object) {
|
|
i::Object* o = reinterpret_cast<i::Object*>(object);
|
|
if (!o->IsLayoutDescriptor()) {
|
|
printf("Please provide a layout descriptor\n");
|
|
} else {
|
|
reinterpret_cast<i::LayoutDescriptor*>(object)->Print();
|
|
}
|
|
}
|
|
|
|
extern void _v8_internal_Print_TransitionArray(void* object) {
|
|
if (reinterpret_cast<i::Object*>(object)->IsSmi()) {
|
|
printf("Please provide a transition array\n");
|
|
} else {
|
|
reinterpret_cast<i::TransitionArray*>(object)->Print();
|
|
}
|
|
}
|
|
|
|
extern void _v8_internal_Print_StackTrace() {
|
|
i::Isolate* isolate = i::Isolate::Current();
|
|
isolate->PrintStack(stdout);
|
|
}
|
|
|
|
extern void _v8_internal_Print_TransitionTree(void* object) {
|
|
i::Object* o = reinterpret_cast<i::Object*>(object);
|
|
if (!o->IsMap()) {
|
|
printf("Please provide a valid Map\n");
|
|
} else {
|
|
#if defined(DEBUG) || defined(OBJECT_PRINT)
|
|
i::DisallowHeapAllocation no_gc;
|
|
i::TransitionsAccessor transitions(reinterpret_cast<i::Map*>(object),
|
|
&no_gc);
|
|
transitions.PrintTransitionTree();
|
|
#endif
|
|
}
|
|
}
|