| // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| #include "vm/canonical_tables.h" | |
| #include "vm/closure_functions_cache.h" | |
| #include "vm/compiler/assembler/disassembler.h" | |
| #include "vm/compiler/ffi/native_type.h" | |
| #include "vm/debugger.h" | |
| #include "vm/object.h" | |
| #include "vm/object_graph.h" | |
| #include "vm/object_store.h" | |
| #include "vm/resolver.h" | |
| #include "vm/stub_code.h" | |
| #include "vm/symbols.h" | |
| namespace dart { | |
| #ifndef PRODUCT | |
| static void AddNameProperties(JSONObject* jsobj, | |
| const char* name, | |
| const char* vm_name) { | |
| jsobj->AddProperty("name", name); | |
| if (strcmp(name, vm_name) != 0) { | |
| jsobj->AddProperty("_vmName", vm_name); | |
| } | |
| } | |
| void Object::AddCommonObjectProperties(JSONObject* jsobj, | |
| const char* protocol_type, | |
| bool ref) const { | |
| const char* vm_type = JSONType(); | |
| bool same_type = (strcmp(protocol_type, vm_type) == 0); | |
| if (ref) { | |
| jsobj->AddPropertyF("type", "@%s", protocol_type); | |
| } else { | |
| jsobj->AddProperty("type", protocol_type); | |
| } | |
| if (!same_type) { | |
| jsobj->AddProperty("_vmType", vm_type); | |
| } | |
| if (!ref || IsInstance() || IsNull()) { | |
| // TODO(turnidge): Provide the type arguments here too? | |
| const Class& cls = Class::Handle(this->clazz()); | |
| jsobj->AddProperty("class", cls); | |
| } | |
| if (!ref) { | |
| if (ptr()->IsHeapObject()) { | |
| jsobj->AddProperty("size", ptr()->untag()->HeapSize()); | |
| } else { | |
| jsobj->AddProperty("size", (intptr_t)0); | |
| } | |
| } | |
| } | |
| void Object::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| jsobj.AddServiceId(*this); | |
| if (ref) { | |
| return; | |
| } | |
| } | |
| void Object::PrintJSON(JSONStream* stream, bool ref) const { | |
| if (IsNull()) { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Instance", ref); | |
| jsobj.AddProperty("kind", "Null"); | |
| jsobj.AddFixedServiceId("objects/null"); | |
| jsobj.AddProperty("valueAsString", "null"); | |
| } else { | |
| PrintJSONImpl(stream, ref); | |
| } | |
| } | |
| void Object::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const { | |
| UNREACHABLE(); | |
| } | |
| void Object::PrintImplementationFields(JSONStream* stream) const { | |
| JSONObject jsobj(stream); | |
| jsobj.AddProperty("type", "ImplementationFields"); | |
| JSONArray jsarr_fields(&jsobj, "fields"); | |
| if (!IsNull()) { | |
| PrintImplementationFieldsImpl(jsarr_fields); | |
| } | |
| } | |
| static const char* FfiTypeDisplayName(Zone* zone, | |
| const compiler::ffi::NativeType& type) { | |
| if (type.IsCompound()) { | |
| const char* name = type.AsCompound().name(); | |
| if (name != nullptr) { | |
| return name; | |
| } | |
| } | |
| return type.ToCString(zone, /*multi_line=*/false, /*verbose=*/false); | |
| } | |
| static void PrintFfiCompoundLayout( | |
| Zone* zone, | |
| JSONObject* layout, | |
| const compiler::ffi::NativeCompoundType& compound, | |
| intptr_t base_offset) { | |
| // Only structs have a member offset table, the members of a union all start | |
| // at the union's own offset. | |
| const bool is_struct = compound.IsStruct(); | |
| layout->AddProperty("kind", is_struct ? "struct" : "union"); | |
| const auto& members = compound.members(); | |
| { | |
| JSONArray fields_arr(layout, "fields"); | |
| for (intptr_t i = 0; i < members.length(); ++i) { | |
| const compiler::ffi::NativeType& field_nt = members[i].type(); | |
| const intptr_t offset = | |
| base_offset + | |
| (is_struct ? compound.AsStruct().member_offsets()[i] : 0); | |
| const bool is_array = field_nt.IsArray(); | |
| JSONObject field_obj(&fields_arr); | |
| field_obj.AddProperty("name", members[i].name()); | |
| field_obj.AddProperty( | |
| "nativeType", | |
| is_array ? "Array" : FfiTypeDisplayName(zone, field_nt)); | |
| field_obj.AddProperty64("offset", offset); | |
| field_obj.AddProperty64("size", field_nt.SizeInBytes()); | |
| if (is_array) { | |
| // Multi-dimensional arrays are flattened into a single one by the FFI | |
| // transformer, so the element type is never itself an array. | |
| const auto& array = field_nt.AsArray(); | |
| field_obj.AddProperty64("length", array.length()); | |
| field_obj.AddProperty("arrayElementType", | |
| FfiTypeDisplayName(zone, array.element_type())); | |
| if (array.element_type().IsCompound()) { | |
| // The nested layout describes the first element, the remaining | |
| // elements repeat it at multiples of the element size. | |
| PrintFfiCompoundLayout(zone, &field_obj, | |
| array.element_type().AsCompound(), offset); | |
| } | |
| } else if (field_nt.IsCompound()) { | |
| PrintFfiCompoundLayout(zone, &field_obj, field_nt.AsCompound(), offset); | |
| } | |
| } | |
| } | |
| } | |
| static bool IsFfiCompoundSubclass(Zone* zone, | |
| const Class& cls, | |
| const Class& base_cls) { | |
| if (base_cls.IsNull()) { | |
| return false; | |
| } | |
| Class& super_cls = Class::Handle(zone, cls.SuperClass()); | |
| while (!super_cls.IsNull() && super_cls.ptr() != base_cls.ptr()) { | |
| super_cls = super_cls.SuperClass(); | |
| } | |
| if (super_cls.IsNull()) { | |
| return false; | |
| } | |
| const Type& cls_type = Type::Handle(zone, cls.DeclarationType()); | |
| const Type& base_type = Type::Handle(zone, base_cls.DeclarationType()); | |
| return cls_type.IsSubtypeOf(base_type, Heap::kNew); | |
| } | |
| static void PrintFfiLayout(JSONObject* jsobj, const Class& cls) { | |
| Thread* thread = Thread::Current(); | |
| Zone* zone = thread->zone(); | |
| auto* object_store = thread->isolate_group()->object_store(); | |
| const Class& struct_base_cls = | |
| Class::Handle(zone, object_store->ffi_struct_class()); | |
| const Class& union_base_cls = | |
| Class::Handle(zone, object_store->ffi_union_class()); | |
| if (!IsFfiCompoundSubclass(zone, cls, struct_base_cls) && | |
| !IsFfiCompoundSubclass(zone, cls, union_base_cls)) { | |
| return; | |
| } | |
| const Type& cls_type = Type::Handle(zone, cls.DeclarationType()); | |
| const char* error = nullptr; | |
| const compiler::ffi::NativeType* nt = | |
| compiler::ffi::NativeType::FromAbstractType(zone, cls_type, &error); | |
| if (nt == nullptr || !nt->IsCompound()) { | |
| return; | |
| } | |
| const auto& compound = nt->AsCompound(); | |
| JSONObject layout(jsobj, "ffiLayout"); | |
| layout.AddProperty("size", compound.SizeInBytes()); | |
| PrintFfiCompoundLayout(zone, &layout, compound, /*base_offset=*/0); | |
| } | |
| void Class::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Isolate* isolate = Isolate::Current(); | |
| JSONObject jsobj(stream); | |
| if ((ptr() == Class::null()) || (id() == kFreeListElement)) { | |
| // TODO(turnidge): This is weird and needs to be changed. | |
| jsobj.AddProperty("type", "null"); | |
| return; | |
| } | |
| AddCommonObjectProperties(&jsobj, "Class", ref); | |
| jsobj.AddFixedServiceId("classes/%" Pd "", id()); | |
| const String& scrubbed_name = String::Handle(ScrubbedName()); | |
| const String& vm_name = String::Handle(Name()); | |
| AddNameProperties(&jsobj, scrubbed_name.ToCString(), vm_name.ToCString()); | |
| const Script& script = Script::Handle(this->script()); | |
| if (!script.IsNull()) { | |
| jsobj.AddLocation(script, token_pos(), end_token_pos()); | |
| } | |
| jsobj.AddProperty("library", Object::Handle(library())); | |
| const intptr_t num_type_params = NumTypeParameters(); | |
| if (num_type_params > 0) { | |
| JSONArray jsarr(&jsobj, "typeParameters"); | |
| TypeParameter& type_param = TypeParameter::Handle(); | |
| for (intptr_t i = 0; i < num_type_params; ++i) { | |
| type_param = TypeParameterAt(i); | |
| jsarr.AddValue(type_param); | |
| } | |
| } | |
| if (ref) { | |
| return; | |
| } | |
| const Error& err = Error::Handle(EnsureIsFinalized(Thread::Current())); | |
| if (!err.IsNull()) { | |
| jsobj.AddProperty("error", err); | |
| } | |
| jsobj.AddProperty("abstract", is_abstract()); | |
| jsobj.AddProperty("const", is_const()); | |
| jsobj.AddProperty("isSealed", is_sealed()); | |
| jsobj.AddProperty("isMixinClass", is_mixin_class()); | |
| jsobj.AddProperty("isBaseClass", is_base_class()); | |
| jsobj.AddProperty("isInterfaceClass", is_interface_class()); | |
| jsobj.AddProperty("isFinal", is_final()); | |
| jsobj.AddProperty("_finalized", is_finalized()); | |
| jsobj.AddProperty("_implemented", is_implemented()); | |
| jsobj.AddProperty("_patch", false); | |
| jsobj.AddProperty("traceAllocations", TraceAllocation(isolate->group())); | |
| if (err.IsNull() && is_finalized() && !IsTopLevel()) { | |
| PrintFfiLayout(&jsobj, *this); | |
| } | |
| const Class& superClass = Class::Handle(SuperClass()); | |
| if (!superClass.IsNull()) { | |
| jsobj.AddProperty("super", superClass); | |
| } | |
| const AbstractType& superType = AbstractType::Handle(super_type()); | |
| if (!superType.IsNull()) { | |
| jsobj.AddProperty("superType", superType); | |
| } | |
| const Array& interface_array = Array::Handle(interfaces()); | |
| if (is_transformed_mixin_application()) { | |
| Type& mix = Type::Handle(); | |
| mix ^= interface_array.At(interface_array.Length() - 1); | |
| jsobj.AddProperty("mixin", mix); | |
| } | |
| { | |
| JSONArray interfaces_array(&jsobj, "interfaces"); | |
| Type& interface_type = Type::Handle(); | |
| if (!interface_array.IsNull()) { | |
| for (intptr_t i = 0; i < interface_array.Length(); ++i) { | |
| interface_type ^= interface_array.At(i); | |
| interfaces_array.AddValue(interface_type); | |
| } | |
| } | |
| } | |
| { | |
| JSONArray fields_array(&jsobj, "fields"); | |
| const Array& field_array = Array::Handle(fields()); | |
| Field& field = Field::Handle(); | |
| if (!field_array.IsNull()) { | |
| for (intptr_t i = 0; i < field_array.Length(); ++i) { | |
| field ^= field_array.At(i); | |
| fields_array.AddValue(field); | |
| } | |
| } | |
| } | |
| { | |
| JSONArray functions_array(&jsobj, "functions"); | |
| const Array& function_array = Array::Handle(current_functions()); | |
| Function& function = Function::Handle(); | |
| if (!function_array.IsNull()) { | |
| for (intptr_t i = 0; i < function_array.Length(); i++) { | |
| function ^= function_array.At(i); | |
| functions_array.AddValue(function); | |
| } | |
| } | |
| } | |
| { | |
| JSONArray subclasses_array(&jsobj, "subclasses"); | |
| const GrowableObjectArray& subclasses = | |
| GrowableObjectArray::Handle(direct_subclasses_unsafe()); | |
| if (!subclasses.IsNull()) { | |
| Class& subclass = Class::Handle(); | |
| for (intptr_t i = 0; i < subclasses.Length(); ++i) { | |
| // TODO(turnidge): Use the Type directly once regis has added | |
| // types to the vmservice. | |
| subclass ^= subclasses.At(i); | |
| subclasses_array.AddValue(subclass); | |
| } | |
| } | |
| } | |
| } | |
| void Class::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const { | |
| } | |
| void TypeParameters::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "TypeParameters", ref); | |
| jsobj.AddServiceId(*this); | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddProperty("flags", Array::Handle(flags())); | |
| jsobj.AddProperty("names", Array::Handle(names())); | |
| jsobj.AddProperty("bounds", TypeArguments::Handle(bounds())); | |
| jsobj.AddProperty("defaults", TypeArguments::Handle(defaults())); | |
| } | |
| void TypeParameters::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void TypeArguments::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| // The index in the canonical_type_arguments table cannot be used as part of | |
| // the object id (as in typearguments/id), because the indices are not | |
| // preserved when the table grows and the entries get rehashed. Use the ring. | |
| Thread* thread = Thread::Current(); | |
| Zone* zone = thread->zone(); | |
| auto object_store = thread->isolate_group()->object_store(); | |
| CanonicalTypeArgumentsSet typeargs_table( | |
| zone, object_store->canonical_type_arguments()); | |
| const Array& table = | |
| Array::Handle(HashTables::ToArray(typeargs_table, false)); | |
| typeargs_table.Release(); | |
| ASSERT(table.Length() > 0); | |
| AddCommonObjectProperties(&jsobj, "TypeArguments", ref); | |
| jsobj.AddServiceId(*this); | |
| const String& user_name = String::Handle(UserVisibleName()); | |
| const String& vm_name = String::Handle(Name()); | |
| AddNameProperties(&jsobj, user_name.ToCString(), vm_name.ToCString()); | |
| if (ref) { | |
| return; | |
| } | |
| { | |
| JSONArray jsarr(&jsobj, "types"); | |
| AbstractType& type_arg = AbstractType::Handle(); | |
| for (intptr_t i = 0; i < Length(); i++) { | |
| type_arg = TypeAt(i); | |
| jsarr.AddValue(type_arg); | |
| } | |
| } | |
| if (!IsInstantiated()) { | |
| JSONArray jsarr(&jsobj, "_instantiations"); | |
| Array& prior_instantiations = Array::Handle(zone, instantiations()); | |
| TypeArguments& type_args = TypeArguments::Handle(zone); | |
| InstantiationsCacheTable table(prior_instantiations); | |
| for (const auto& tuple : table) { | |
| // Skip unoccupied entries. | |
| if (tuple.Get<Cache::kSentinelIndex>() == Cache::Sentinel()) continue; | |
| JSONObject instantiation(&jsarr); | |
| type_args ^= tuple.Get<Cache::kInstantiatorTypeArgsIndex>(); | |
| instantiation.AddProperty("instantiatorTypeArguments", type_args, true); | |
| type_args = tuple.Get<Cache::kFunctionTypeArgsIndex>(); | |
| instantiation.AddProperty("functionTypeArguments", type_args, true); | |
| type_args = tuple.Get<Cache::kInstantiatedTypeArgsIndex>(); | |
| instantiation.AddProperty("instantiated", type_args, true); | |
| } | |
| } | |
| } | |
| void TypeArguments::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void PatchClass::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void PatchClass::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Function::AddFunctionServiceId(const JSONObject& jsobj) const { | |
| Class& cls = Class::Handle(Owner()); | |
| // Special kinds of functions use indices in their respective lists. | |
| intptr_t id = -1; | |
| const char* selector = nullptr; | |
| // Regular functions known to their owner use their name (percent-encoded). | |
| String& name = String::Handle(this->name()); | |
| if (IsNonImplicitClosureFunction()) { | |
| id = ClosureFunctionsCache::FindClosureIndex(*this); | |
| selector = "closures"; | |
| } else if (IsImplicitClosureFunction()) { | |
| id = cls.FindImplicitClosureFunctionIndex(*this); | |
| selector = "implicit_closures"; | |
| } else if (IsNoSuchMethodDispatcher() || IsInvokeFieldDispatcher()) { | |
| id = cls.FindInvocationDispatcherFunctionIndex(*this); | |
| selector = "dispatchers"; | |
| } else if (IsFieldInitializer()) { | |
| name ^= Field::NameFromInit(name); | |
| const char* encoded_field_name = String::EncodeIRI(name); | |
| if (cls.IsTopLevel()) { | |
| const auto& library = Library::Handle(cls.library()); | |
| const auto& private_key = String::Handle(library.private_key()); | |
| jsobj.AddFixedServiceId("libraries/%s/field_inits/%s", | |
| private_key.ToCString(), encoded_field_name); | |
| } else { | |
| jsobj.AddFixedServiceId("classes/%" Pd "/field_inits/%s", cls.id(), | |
| encoded_field_name); | |
| } | |
| return; | |
| } | |
| if (id != -1) { | |
| ASSERT(selector != nullptr); | |
| if (cls.IsTopLevel()) { | |
| const auto& library = Library::Handle(cls.library()); | |
| const auto& private_key = String::Handle(library.private_key()); | |
| jsobj.AddFixedServiceId("libraries/%s/%s/%" Pd "", | |
| private_key.ToCString(), selector, id); | |
| } else { | |
| jsobj.AddFixedServiceId("classes/%" Pd "/%s/%" Pd "", cls.id(), selector, | |
| id); | |
| } | |
| return; | |
| } | |
| Thread* thread = Thread::Current(); | |
| if (Resolver::ResolveFunction(thread->zone(), cls, name) == ptr()) { | |
| const char* encoded_name = String::EncodeIRI(name); | |
| if (cls.IsTopLevel()) { | |
| const auto& library = Library::Handle(cls.library()); | |
| const auto& private_key = String::Handle(library.private_key()); | |
| jsobj.AddFixedServiceId("libraries/%s/functions/%s", | |
| private_key.ToCString(), encoded_name); | |
| } else { | |
| jsobj.AddFixedServiceId("classes/%" Pd "/functions/%s", cls.id(), | |
| encoded_name); | |
| } | |
| return; | |
| } | |
| // Oddball functions (not known to their owner) fall back to use the object | |
| // id ring. Current known examples are signature functions of closures | |
| // and stubs like 'megamorphic_call_miss'. | |
| jsobj.AddServiceId(*this); | |
| } | |
| void Function::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Class& cls = Class::Handle(Owner()); | |
| ASSERT(!cls.IsNull()); | |
| Error& err = Error::Handle(); | |
| err = cls.EnsureIsFinalized(Thread::Current()); | |
| ASSERT(err.IsNull()); | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Function", ref); | |
| AddFunctionServiceId(jsobj); | |
| const char* user_name = UserVisibleNameCString(); | |
| const String& vm_name = String::Handle(name()); | |
| AddNameProperties(&jsobj, user_name, vm_name.ToCString()); | |
| const Function& parent = Function::Handle(parent_function()); | |
| if (!parent.IsNull()) { | |
| jsobj.AddProperty("owner", parent); | |
| } else if (!cls.IsNull()) { | |
| if (cls.IsTopLevel()) { | |
| const Library& library = Library::Handle(cls.library()); | |
| jsobj.AddProperty("owner", library); | |
| } else { | |
| jsobj.AddProperty("owner", cls); | |
| } | |
| } | |
| const char* kind_string = Function::KindToCString(kind()); | |
| jsobj.AddProperty("_kind", kind_string); | |
| jsobj.AddProperty("static", is_static()); | |
| jsobj.AddProperty("const", is_const()); | |
| jsobj.AddProperty("implicit", IsImplicitGetterOrSetter()); | |
| jsobj.AddProperty("abstract", is_abstract()); | |
| jsobj.AddProperty("_intrinsic", is_intrinsic()); | |
| jsobj.AddProperty("_native", is_native()); | |
| jsobj.AddProperty("isGetter", kind() == UntaggedFunction::kGetterFunction); | |
| jsobj.AddProperty("isSetter", kind() == UntaggedFunction::kSetterFunction); | |
| const Script& script = Script::Handle(this->script()); | |
| if (!script.IsNull()) { | |
| #if defined(DART_PRECOMPILED_RUNTIME) | |
| // Token position information is stripped in AOT snapshots, but the line | |
| // number is still included. | |
| jsobj.AddLocationLine(script, line()); | |
| #else | |
| jsobj.AddLocation(script, token_pos(), end_token_pos()); | |
| #endif // defined(DART_PRECOMPILED_RUNTIME) | |
| } | |
| if (ref) { | |
| return; | |
| } | |
| const FunctionType& sig = FunctionType::Handle(signature()); | |
| jsobj.AddProperty("signature", sig); | |
| Code& code = Code::Handle(CurrentCode()); | |
| if (!code.IsNull()) { | |
| jsobj.AddProperty("code", code); | |
| } | |
| Array& ics = Array::Handle(ic_data_array()); | |
| if (!ics.IsNull()) { | |
| jsobj.AddProperty("_icDataArray", ics); | |
| } | |
| jsobj.AddProperty("_optimizable", is_optimizable()); | |
| jsobj.AddProperty("_inlinable", is_inlinable()); | |
| jsobj.AddProperty("_recognized", IsRecognized()); | |
| code = unoptimized_code(); | |
| if (!code.IsNull()) { | |
| jsobj.AddProperty("_unoptimizedCode", code); | |
| } | |
| jsobj.AddProperty("_usageCounter", usage_counter()); | |
| jsobj.AddProperty("_optimizedCallSiteCount", optimized_call_site_count()); | |
| jsobj.AddProperty("_deoptimizations", | |
| static_cast<intptr_t>(deoptimization_counter())); | |
| if ((kind() == UntaggedFunction::kImplicitGetter) || | |
| (kind() == UntaggedFunction::kImplicitSetter) || | |
| (kind() == UntaggedFunction::kImplicitStaticGetter) || | |
| (kind() == UntaggedFunction::kFieldInitializer)) { | |
| const Field& field = Field::Handle(accessor_field()); | |
| if (!field.IsNull()) { | |
| jsobj.AddProperty("_field", field); | |
| } | |
| } | |
| } | |
| void Function::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void FfiTrampolineData::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void FfiTrampolineData::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Field::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| Class& cls = Class::Handle(Owner()); | |
| String& field_name = String::Handle(name()); | |
| const char* encoded_field_name = String::EncodeIRI(field_name); | |
| AddCommonObjectProperties(&jsobj, "Field", ref); | |
| if (cls.IsTopLevel()) { | |
| const auto& library = Library::Handle(cls.library()); | |
| const auto& private_key = String::Handle(library.private_key()); | |
| jsobj.AddFixedServiceId("libraries/%s/fields/%s", private_key.ToCString(), | |
| encoded_field_name); | |
| } else { | |
| jsobj.AddFixedServiceId("classes/%" Pd "/fields/%s", cls.id(), | |
| encoded_field_name); | |
| } | |
| const char* user_name = UserVisibleNameCString(); | |
| const String& vm_name = String::Handle(name()); | |
| AddNameProperties(&jsobj, user_name, vm_name.ToCString()); | |
| if (cls.IsTopLevel()) { | |
| const Library& library = Library::Handle(cls.library()); | |
| jsobj.AddProperty("owner", library); | |
| } else { | |
| jsobj.AddProperty("owner", cls); | |
| } | |
| AbstractType& declared_type = AbstractType::Handle(type()); | |
| jsobj.AddProperty("declaredType", declared_type); | |
| jsobj.AddProperty("static", is_static()); | |
| jsobj.AddProperty("final", is_final()); | |
| jsobj.AddProperty("const", is_const()); | |
| const class Script& script = Script::Handle(Script()); | |
| if (!script.IsNull()) { | |
| jsobj.AddLocation(script, token_pos(), end_token_pos()); | |
| } | |
| if (ref) { | |
| return; | |
| } | |
| if (is_static()) { | |
| const Object& valueObj = Object::Handle(StaticValue()); | |
| jsobj.AddProperty("staticValue", valueObj); | |
| } | |
| jsobj.AddProperty("_guardNullable", is_nullable()); | |
| if (guarded_cid() == kIllegalCid) { | |
| jsobj.AddProperty("_guardClass", "unknown"); | |
| } else if (guarded_cid() == kDynamicCid) { | |
| jsobj.AddProperty("_guardClass", "dynamic"); | |
| } else { | |
| ClassTable* table = IsolateGroup::Current()->class_table(); | |
| ASSERT(table->IsValidIndex(guarded_cid())); | |
| cls = table->At(guarded_cid()); | |
| jsobj.AddProperty("_guardClass", cls); | |
| } | |
| if (guarded_list_length() == kUnknownFixedLength) { | |
| jsobj.AddProperty("_guardLength", "unknown"); | |
| } else if (guarded_list_length() == kNoFixedLength) { | |
| jsobj.AddProperty("_guardLength", "variable"); | |
| } else { | |
| jsobj.AddPropertyF("_guardLength", "%" Pd, guarded_list_length()); | |
| } | |
| } | |
| void Field::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const { | |
| } | |
| // See also Dart_ScriptGetTokenInfo. | |
| void Script::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Script", ref); | |
| const String& uri = String::Handle(url()); | |
| ASSERT(!uri.IsNull()); | |
| const char* encoded_uri = String::EncodeIRI(uri); | |
| const Library& lib = Library::Handle(FindLibrary()); | |
| if (lib.IsNull()) { | |
| jsobj.AddServiceId(*this); | |
| } else { | |
| const String& lib_id = String::Handle(lib.private_key()); | |
| jsobj.AddFixedServiceId("libraries/%s/scripts/%s/%" Px64 "", | |
| lib_id.ToCString(), encoded_uri, load_timestamp()); | |
| } | |
| jsobj.AddPropertyStr("uri", uri); | |
| jsobj.AddProperty("_kind", "kernel"); | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddPropertyTimeMillis("_loadTime", load_timestamp()); | |
| if (!lib.IsNull()) { | |
| jsobj.AddProperty("library", lib); | |
| } | |
| const String& source = String::Handle(Source()); | |
| jsobj.AddProperty("lineOffset", line_offset()); | |
| jsobj.AddProperty("columnOffset", col_offset()); | |
| if (!source.IsNull()) { | |
| jsobj.AddPropertyStr("source", source); | |
| } | |
| // Print the line number table | |
| const GrowableObjectArray& lineNumberArray = | |
| GrowableObjectArray::Handle(GenerateLineNumberArray()); | |
| if (!lineNumberArray.IsNull() && (lineNumberArray.Length() > 0)) { | |
| JSONArray tokenPosTable(&jsobj, "tokenPosTable"); | |
| Object& value = Object::Handle(); | |
| intptr_t pos = 0; | |
| // Skip leading null. | |
| ASSERT(lineNumberArray.Length() > 0); | |
| value = lineNumberArray.At(pos); | |
| ASSERT(value.IsNull()); | |
| pos++; | |
| while (pos < lineNumberArray.Length()) { | |
| JSONArray lineInfo(&tokenPosTable); | |
| while (pos < lineNumberArray.Length()) { | |
| value = lineNumberArray.At(pos); | |
| pos++; | |
| if (value.IsNull()) { | |
| break; | |
| } | |
| const Smi& smi = Smi::Cast(value); | |
| lineInfo.AddValue(smi.Value()); | |
| } | |
| } | |
| } | |
| } | |
| void Script::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| static void PrintShowHideNamesToJSON(JSONObject* jsobj, const Namespace& ns) { | |
| Array& arr = Array::Handle(); | |
| String& name = String::Handle(); | |
| arr ^= ns.show_names(); | |
| if (!arr.IsNull()) { | |
| JSONArray jsarr(jsobj, "shows"); | |
| for (intptr_t i = 0; i < arr.Length(); ++i) { | |
| name ^= arr.At(i); | |
| jsarr.AddValue(name.ToCString()); | |
| } | |
| } | |
| arr ^= ns.hide_names(); | |
| if (!arr.IsNull()) { | |
| JSONArray jsarr(jsobj, "hides"); | |
| for (intptr_t i = 0; i < arr.Length(); ++i) { | |
| name ^= arr.At(i); | |
| jsarr.AddValue(name.ToCString()); | |
| } | |
| } | |
| } | |
| void Library::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| const String& id = String::Handle(private_key()); | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Library", ref); | |
| jsobj.AddFixedServiceId("libraries/%s", id.ToCString()); | |
| const String& vm_name = String::Handle(name()); | |
| const char* scrubbed_name = String::ScrubName(vm_name); | |
| AddNameProperties(&jsobj, scrubbed_name, vm_name.ToCString()); | |
| const String& library_url = String::Handle(url()); | |
| jsobj.AddPropertyStr("uri", library_url); | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddProperty("debuggable", IsDebuggable()); | |
| { | |
| JSONArray jsarr(&jsobj, "classes"); | |
| ClassDictionaryIterator class_iter(*this); | |
| Class& klass = Class::Handle(); | |
| while (class_iter.HasNext()) { | |
| klass = class_iter.GetNextClass(); | |
| jsarr.AddValue(klass); | |
| } | |
| } | |
| { | |
| JSONArray jsarr(&jsobj, "dependencies"); | |
| Namespace& ns = Namespace::Handle(); | |
| Library& target = Library::Handle(); | |
| // Unprefixed imports. | |
| Array& imports = Array::Handle(this->imports()); | |
| for (intptr_t i = 0; i < imports.Length(); i++) { | |
| ns ^= imports.At(i); | |
| if (ns.IsNull()) continue; | |
| JSONObject jsdep(&jsarr); | |
| jsdep.AddProperty("isDeferred", false); | |
| jsdep.AddProperty("isExport", false); | |
| jsdep.AddProperty("isImport", true); | |
| target = ns.target(); | |
| jsdep.AddProperty("target", target); | |
| PrintShowHideNamesToJSON(&jsdep, ns); | |
| } | |
| // Exports. | |
| const Array& exports = Array::Handle(this->exports()); | |
| for (intptr_t i = 0; i < exports.Length(); i++) { | |
| ns ^= exports.At(i); | |
| if (ns.IsNull()) continue; | |
| JSONObject jsdep(&jsarr); | |
| jsdep.AddProperty("isDeferred", false); | |
| jsdep.AddProperty("isExport", true); | |
| jsdep.AddProperty("isImport", false); | |
| target = ns.target(); | |
| jsdep.AddProperty("target", target); | |
| PrintShowHideNamesToJSON(&jsdep, ns); | |
| } | |
| // Prefixed imports. | |
| DictionaryIterator entries(*this); | |
| Object& entry = Object::Handle(); | |
| LibraryPrefix& prefix = LibraryPrefix::Handle(); | |
| String& prefix_name = String::Handle(); | |
| while (entries.HasNext()) { | |
| entry = entries.GetNext(); | |
| if (entry.IsLibraryPrefix()) { | |
| prefix ^= entry.ptr(); | |
| imports = prefix.imports(); | |
| if (!imports.IsNull()) { | |
| for (intptr_t i = 0; i < imports.Length(); i++) { | |
| ns ^= imports.At(i); | |
| if (ns.IsNull()) continue; | |
| JSONObject jsdep(&jsarr); | |
| jsdep.AddProperty("isDeferred", prefix.is_deferred_load()); | |
| jsdep.AddProperty("isExport", false); | |
| jsdep.AddProperty("isImport", true); | |
| prefix_name = prefix.name(); | |
| ASSERT(!prefix_name.IsNull()); | |
| jsdep.AddProperty("prefix", prefix_name.ToCString()); | |
| target = ns.target(); | |
| jsdep.AddProperty("target", target); | |
| PrintShowHideNamesToJSON(&jsdep, ns); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| { | |
| JSONArray jsarr(&jsobj, "variables"); | |
| DictionaryIterator entries(*this); | |
| Object& entry = Object::Handle(); | |
| while (entries.HasNext()) { | |
| entry = entries.GetNext(); | |
| if (entry.IsField()) { | |
| jsarr.AddValue(entry); | |
| } | |
| } | |
| } | |
| { | |
| JSONArray jsarr(&jsobj, "functions"); | |
| DictionaryIterator entries(*this); | |
| Object& entry = Object::Handle(); | |
| while (entries.HasNext()) { | |
| entry = entries.GetNext(); | |
| if (entry.IsFunction()) { | |
| const Function& func = Function::Cast(entry); | |
| if (func.kind() == UntaggedFunction::kRegularFunction || | |
| func.kind() == UntaggedFunction::kGetterFunction || | |
| func.kind() == UntaggedFunction::kSetterFunction) { | |
| jsarr.AddValue(func); | |
| } | |
| } | |
| } | |
| } | |
| { | |
| JSONArray jsarr(&jsobj, "scripts"); | |
| Array& scripts = Array::Handle(LoadedScripts()); | |
| Script& script = Script::Handle(); | |
| for (intptr_t i = 0; i < scripts.Length(); i++) { | |
| script ^= scripts.At(i); | |
| jsarr.AddValue(script); | |
| } | |
| } | |
| } | |
| void Library::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void LibraryPrefix::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void LibraryPrefix::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Namespace::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void Namespace::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void KernelProgramInfo::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void KernelProgramInfo::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Instructions::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void Instructions::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void InstructionsSection::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void InstructionsSection::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void InstructionsTable::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void InstructionsTable::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void WeakSerializationReference::PrintJSONImpl(JSONStream* stream, | |
| bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| jsobj.AddServiceId(*this); | |
| if (ref) return; | |
| auto& obj = Object::Handle(target()); | |
| jsobj.AddProperty("target", obj); | |
| } | |
| void WeakSerializationReference::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void WeakArray::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("length", Length()); | |
| if (ref) { | |
| return; | |
| } | |
| intptr_t offset; | |
| intptr_t count; | |
| stream->ComputeOffsetAndCount(Length(), &offset, &count); | |
| if (offset > 0) { | |
| jsobj.AddProperty("offset", offset); | |
| } | |
| if (count < Length()) { | |
| jsobj.AddProperty("count", count); | |
| } | |
| intptr_t limit = offset + count; | |
| ASSERT(limit <= Length()); | |
| { | |
| JSONArray jsarr(&jsobj, "elements"); | |
| Object& element = Object::Handle(); | |
| for (intptr_t index = offset; index < limit; index++) { | |
| element = At(index); | |
| jsarr.AddValue(element); | |
| } | |
| } | |
| } | |
| void WeakArray::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void ObjectPool::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("length", Length()); | |
| if (ref) { | |
| return; | |
| } | |
| { | |
| JSONArray jsarr(&jsobj, "_entries"); | |
| uword imm; | |
| Object& obj = Object::Handle(); | |
| for (intptr_t i = 0; i < Length(); i++) { | |
| JSONObject jsentry(stream); | |
| jsentry.AddProperty("offset", OffsetFromIndex(i)); | |
| switch (TypeAt(i)) { | |
| case ObjectPool::EntryType::kTaggedObject: | |
| obj = ObjectAt(i); | |
| jsentry.AddProperty("kind", "Object"); | |
| jsentry.AddProperty("value", obj); | |
| break; | |
| case ObjectPool::EntryType::kImmediate: | |
| imm = RawValueAt(i); | |
| jsentry.AddProperty("kind", "Immediate"); | |
| jsentry.AddPropertyF("value", "0x%" Px, imm); | |
| break; | |
| case ObjectPool::EntryType::kNativeFunction: | |
| imm = RawValueAt(i); | |
| jsentry.AddProperty("kind", "NativeFunction"); | |
| jsentry.AddPropertyF("value", "0x%" Px, imm); | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } | |
| } | |
| } | |
| void ObjectPool::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void PcDescriptors::PrintToJSONObject(JSONObject* jsobj, bool ref) const { | |
| AddCommonObjectProperties(jsobj, "Object", ref); | |
| // TODO(johnmccutchan): Generate a stable id. PcDescriptors hang off a Code | |
| // object but do not have a back reference to generate an ID. | |
| jsobj->AddServiceId(*this); | |
| if (ref) { | |
| return; | |
| } | |
| JSONArray members(jsobj, "members"); | |
| Iterator iter(*this, UntaggedPcDescriptors::kAnyKind); | |
| while (iter.MoveNext()) { | |
| JSONObject descriptor(&members); | |
| descriptor.AddPropertyF("pcOffset", "%" Px "", iter.PcOffset()); | |
| descriptor.AddProperty("kind", KindToCString(iter.Kind())); | |
| descriptor.AddProperty("deoptId", iter.DeoptId()); | |
| // TODO(turnidge): Use AddLocation instead. | |
| descriptor.AddProperty("tokenPos", iter.TokenPos()); | |
| descriptor.AddProperty("tryIndex", iter.TryIndex()); | |
| } | |
| } | |
| void PcDescriptors::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintToJSONObject(&jsobj, ref); | |
| } | |
| void PcDescriptors::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void CodeSourceMap::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void CodeSourceMap::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void CompressedStackMaps::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void CompressedStackMaps::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void LocalVarDescriptor::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void LocalVarDescriptor::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void LocalVarDescriptors::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| // TODO(johnmccutchan): Generate a stable id. LocalVarDescriptors hang off | |
| // a Code object but do not have a back reference to generate an ID. | |
| jsobj.AddServiceId(*this); | |
| if (ref) { | |
| return; | |
| } | |
| JSONArray members(&jsobj, "members"); | |
| String& var_name = String::Handle(); | |
| for (intptr_t i = 0; i < Length(); i++) { | |
| UntaggedLocalVarDescriptors::VarInfo info; | |
| var_name = GetName(i); | |
| GetInfo(i, &info); | |
| JSONObject var(&members); | |
| var.AddProperty("name", var_name.ToCString()); | |
| var.AddProperty("index", static_cast<intptr_t>(info.index())); | |
| var.AddProperty("declarationTokenPos", info.declaration_pos); | |
| var.AddProperty("scopeStartTokenPos", info.begin_pos); | |
| var.AddProperty("scopeEndTokenPos", info.end_pos); | |
| var.AddProperty("scopeId", static_cast<intptr_t>(info.scope_id)); | |
| var.AddProperty("kind", KindToCString(info.kind())); | |
| } | |
| } | |
| void LocalVarDescriptors::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void ExceptionHandlers::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void ExceptionHandlers::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void SingleTargetCache::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("_target", Code::Handle(target())); | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddProperty("_lowerLimit", lower_limit()); | |
| jsobj.AddProperty("_upperLimit", upper_limit()); | |
| } | |
| void SingleTargetCache::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void UnlinkedCall::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("_selector", String::Handle(target_name()).ToCString()); | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddProperty("_argumentsDescriptor", | |
| Array::Handle(arguments_descriptor())); | |
| } | |
| void UnlinkedCall::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void MonomorphicSmiableCall::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("_expectedClassId", Smi::Handle(Smi::New(expected_cid()))); | |
| if (ref) { | |
| return; | |
| } | |
| } | |
| void MonomorphicSmiableCall::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void CallSiteData::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| UNREACHABLE(); | |
| } | |
| void CallSiteData::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const { | |
| UNREACHABLE(); | |
| } | |
| void ICData::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("_owner", Object::Handle(Owner())); | |
| jsobj.AddProperty("_selector", String::Handle(target_name()).ToCString()); | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddProperty("_argumentsDescriptor", | |
| Object::Handle(arguments_descriptor())); | |
| jsobj.AddProperty("_entries", Object::Handle(entries())); | |
| } | |
| void ICData::PrintToJSONArray(const JSONArray& jsarray, | |
| TokenPosition token_pos) const { | |
| auto class_table = IsolateGroup::Current()->class_table(); | |
| Class& cls = Class::Handle(); | |
| Function& func = Function::Handle(); | |
| JSONObject jsobj(&jsarray); | |
| jsobj.AddProperty("name", String::Handle(target_name()).ToCString()); | |
| jsobj.AddProperty("tokenPos", static_cast<intptr_t>(token_pos.Serialize())); | |
| // TODO(rmacnak): Figure out how to stringify DeoptReasons(). | |
| // jsobj.AddProperty("deoptReasons", ...); | |
| JSONArray cache_entries(&jsobj, "cacheEntries"); | |
| for (intptr_t i = 0; i < NumberOfChecks(); i++) { | |
| JSONObject cache_entry(&cache_entries); | |
| func = GetTargetAt(i); | |
| intptr_t count = GetCountAt(i); | |
| if (!is_static_call()) { | |
| intptr_t cid = GetReceiverClassIdAt(i); | |
| cls = class_table->At(cid); | |
| cache_entry.AddProperty("receiver", cls); | |
| } | |
| cache_entry.AddProperty("target", func); | |
| cache_entry.AddProperty("count", count); | |
| } | |
| } | |
| void ICData::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Code::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Code", ref); | |
| jsobj.AddFixedServiceId("code/%" Px64 "-%" Px "", compile_timestamp(), | |
| PayloadStart()); | |
| const char* qualified_name = QualifiedName( | |
| NameFormattingParams(kUserVisibleName, NameDisambiguation::kNo)); | |
| const char* vm_name = Name(); | |
| AddNameProperties(&jsobj, qualified_name, vm_name); | |
| const bool is_stub = | |
| IsStubCode() || IsAllocationStubCode() || IsTypeTestStubCode(); | |
| if (is_stub) { | |
| jsobj.AddProperty("kind", "Stub"); | |
| } else { | |
| jsobj.AddProperty("kind", "Dart"); | |
| } | |
| jsobj.AddProperty("_optimized", is_optimized()); | |
| const Object& obj = Object::Handle(owner()); | |
| if (obj.IsFunction()) { | |
| const Function& func = Function::Cast(obj); | |
| jsobj.AddProperty("_intrinsic", func.is_intrinsic()); | |
| jsobj.AddProperty("_native", func.is_native()); | |
| } else { | |
| jsobj.AddProperty("_intrinsic", false); | |
| jsobj.AddProperty("_native", false); | |
| } | |
| if (obj.IsFunction()) { | |
| jsobj.AddProperty("function", obj); | |
| } else { | |
| // Generate a fake function reference. | |
| JSONObject func(&jsobj, "function"); | |
| func.AddProperty("type", "@Function"); | |
| func.AddProperty("_kind", "Stub"); | |
| ASSERT(strcmp(qualified_name, vm_name) == 0); | |
| func.AddProperty("name", vm_name); | |
| AddNameProperties(&func, vm_name, vm_name); | |
| } | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddPropertyF("_startAddress", "%" Px "", PayloadStart()); | |
| jsobj.AddPropertyF("_endAddress", "%" Px "", PayloadStart() + Size()); | |
| jsobj.AddProperty("_alive", is_alive()); | |
| const ObjectPool& object_pool = ObjectPool::Handle(GetObjectPool()); | |
| jsobj.AddProperty("_objectPool", object_pool); | |
| { | |
| JSONArray jsarr(&jsobj, "_disassembly"); | |
| if (is_alive()) { | |
| // Only disassemble alive code objects. | |
| DisassembleToJSONStream formatter(jsarr); | |
| Disassemble(&formatter); | |
| } | |
| } | |
| const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors()); | |
| if (!descriptors.IsNull()) { | |
| JSONObject desc(&jsobj, "_descriptors"); | |
| descriptors.PrintToJSONObject(&desc, false); | |
| } | |
| PrintJSONInlineIntervals(&jsobj); | |
| } | |
| void Code::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const {} | |
| void Bytecode::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| // N.B. This is polymorphic with Code. | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Code", ref); | |
| int64_t compile_timestamp = 0; | |
| jsobj.AddFixedServiceId("code/%" Px64 "-%" Px "", compile_timestamp, | |
| PayloadStart()); | |
| const char* qualified_name = QualifiedName(); | |
| const char* vm_name = Name(); | |
| AddNameProperties(&jsobj, qualified_name, vm_name); | |
| jsobj.AddProperty("kind", "Dart"); | |
| jsobj.AddProperty("_optimized", false); | |
| jsobj.AddProperty("_intrinsic", false); | |
| jsobj.AddProperty("_native", false); | |
| if (ref) { | |
| return; | |
| } | |
| const Function& fun = Function::Handle(function()); | |
| jsobj.AddProperty("function", fun); | |
| jsobj.AddPropertyF("_startAddress", "%" Px "", PayloadStart()); | |
| jsobj.AddPropertyF("_endAddress", "%" Px "", PayloadStart() + Size()); | |
| jsobj.AddProperty("_alive", true); | |
| const ObjectPool& obj_pool = ObjectPool::Handle(object_pool()); | |
| jsobj.AddProperty("_objectPool", obj_pool); | |
| { | |
| JSONArray jsarr(&jsobj, "_disassembly"); | |
| DisassembleToJSONStream formatter(jsarr); | |
| Disassemble(&formatter); | |
| } | |
| const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors()); | |
| if (!descriptors.IsNull()) { | |
| JSONObject desc(&jsobj, "_descriptors"); | |
| descriptors.PrintToJSONObject(&desc, false); | |
| } | |
| { | |
| JSONArray inlined_functions(&jsobj, "_inlinedFunctions"); | |
| } | |
| { | |
| JSONArray inline_intervals(&jsobj, "_inlinedIntervals"); | |
| } | |
| } | |
| void Bytecode::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Context::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| // TODO(turnidge): Should the user level type for Context be Context | |
| // or Object? | |
| AddCommonObjectProperties(&jsobj, "Context", ref); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("length", num_variables()); | |
| if (ref) { | |
| return; | |
| } | |
| const Context& parent_context = Context::Handle(parent()); | |
| if (!parent_context.IsNull()) { | |
| jsobj.AddProperty("parent", parent_context); | |
| } | |
| JSONArray jsarr(&jsobj, "variables"); | |
| Object& var = Object::Handle(); | |
| for (intptr_t index = 0; index < num_variables(); index++) { | |
| var = At(index); | |
| JSONObject jselement(&jsarr); | |
| jselement.AddProperty("value", var); | |
| } | |
| } | |
| void Context::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void ContextScope::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void ContextScope::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Sentinel::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| // Handle certain special sentinel values. | |
| if (ptr() == Object::sentinel().ptr()) { | |
| JSONObject jsobj(stream); | |
| jsobj.AddProperty("type", "Sentinel"); | |
| jsobj.AddProperty("kind", "NotInitialized"); | |
| jsobj.AddProperty("valueAsString", "<not initialized>"); | |
| return; | |
| } else if (ptr() == Object::optimized_out().ptr()) { | |
| JSONObject jsobj(stream); | |
| jsobj.AddProperty("type", "Sentinel"); | |
| jsobj.AddProperty("kind", "OptimizedOut"); | |
| jsobj.AddProperty("valueAsString", "<optimized out>"); | |
| return; | |
| } | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void Sentinel::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void MegamorphicCache::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("_selector", String::Handle(target_name()).ToCString()); | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddProperty("_buckets", Object::Handle(buckets())); | |
| jsobj.AddProperty("_mask", mask()); | |
| jsobj.AddProperty("_argumentsDescriptor", | |
| Object::Handle(arguments_descriptor())); | |
| } | |
| void MegamorphicCache::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void SubtypeTestCache::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| jsobj.AddServiceId(*this); | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddProperty("_cache", Array::Handle(cache())); | |
| } | |
| void SubtypeTestCache::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void LoadingUnit::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Object", ref); | |
| jsobj.AddServiceId(*this); | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddProperty("_parent", LoadingUnit::Handle(parent())); | |
| jsobj.AddProperty("_baseObjects", Array::Handle(base_objects())); | |
| jsobj.AddProperty("_id", static_cast<intptr_t>(id())); | |
| jsobj.AddProperty("_loaded", loaded()); | |
| jsobj.AddProperty("_loadOutstanding", load_outstanding()); | |
| } | |
| void LoadingUnit::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Error::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| UNREACHABLE(); | |
| } | |
| void Error::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const { | |
| UNREACHABLE(); | |
| } | |
| void ApiError::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Error", ref); | |
| jsobj.AddProperty("kind", "InternalError"); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("message", ToErrorCString()); | |
| } | |
| void ApiError::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void LanguageError::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Error", ref); | |
| jsobj.AddProperty("kind", "LanguageError"); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("message", ToErrorCString()); | |
| } | |
| void LanguageError::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void UnhandledException::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Error", ref); | |
| jsobj.AddProperty("kind", "UnhandledException"); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("message", ToErrorCString()); | |
| if (ref) { | |
| return; | |
| } | |
| Instance& instance = Instance::Handle(); | |
| instance = exception(); | |
| jsobj.AddProperty("exception", instance); | |
| instance = stacktrace(); | |
| jsobj.AddProperty("stacktrace", instance); | |
| } | |
| void UnhandledException::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void UnwindError::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| AddCommonObjectProperties(&jsobj, "Error", ref); | |
| jsobj.AddProperty("kind", "TerminationError"); | |
| jsobj.AddServiceId(*this); | |
| jsobj.AddProperty("message", ToErrorCString()); | |
| jsobj.AddProperty("_is_user_initiated", is_user_initiated()); | |
| } | |
| void UnwindError::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Instance::PrintSharedInstanceJSON(JSONObject* jsobj, | |
| bool ref, | |
| bool include_id) const { | |
| AddCommonObjectProperties(jsobj, "Instance", ref); | |
| { | |
| NoSafepointScope safepoint_scope; | |
| uint32_t hash_code = HeapSnapshotWriter::GetHeapSnapshotIdentityHash( | |
| Thread::Current(), ptr()); | |
| jsobj->AddProperty64("identityHashCode", hash_code); | |
| } | |
| if (include_id) { | |
| jsobj->AddServiceId(*this); | |
| } | |
| if (ref) { | |
| return; | |
| } | |
| // Add all fields in layout order, from superclass to subclass. | |
| GrowableArray<Class*> classes; | |
| Class& cls = Class::Handle(this->clazz()); | |
| if (IsClosure()) { | |
| // Closure fields are not instances. Skip them. | |
| cls = cls.SuperClass(); | |
| } | |
| do { | |
| classes.Add(&Class::Handle(cls.ptr())); | |
| cls = cls.SuperClass(); | |
| } while (!cls.IsNull()); | |
| Array& field_array = Array::Handle(); | |
| Field& field = Field::Handle(); | |
| Object& field_value = Object::Handle(); | |
| { | |
| JSONArray jsarr(jsobj, "fields"); | |
| for (intptr_t i = classes.length() - 1; i >= 0; i--) { | |
| field_array = classes[i]->fields(); | |
| if (!field_array.IsNull()) { | |
| for (intptr_t j = 0; j < field_array.Length(); j++) { | |
| field ^= field_array.At(j); | |
| if (!field.is_static()) { | |
| field_value = GetField(field); | |
| JSONObject jsfield(&jsarr); | |
| jsfield.AddProperty("decl", field); | |
| jsfield.AddProperty("name", field.UserVisibleNameCString()); | |
| jsfield.AddProperty("value", field_value); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| if (NumNativeFields() > 0) { | |
| JSONArray jsarr(jsobj, "_nativeFields"); | |
| for (intptr_t i = 0; i < NumNativeFields(); i++) { | |
| intptr_t value = GetNativeField(i); | |
| JSONObject jsfield(&jsarr); | |
| jsfield.AddProperty("index", i); | |
| jsfield.AddProperty("value", value); | |
| } | |
| } | |
| } | |
| void Instance::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "PlainInstance"); | |
| GrowableArray<Class*> classes; | |
| Array& field_array = Array::Handle(); | |
| Field& field = Field::Handle(); | |
| Class& cls = Class::Handle(this->clazz()); | |
| if (IsClosure()) { | |
| // Closure fields are not instances. Skip them. | |
| cls = cls.SuperClass(); | |
| } | |
| do { | |
| classes.Add(&Class::Handle(cls.ptr())); | |
| cls = cls.SuperClass(); | |
| } while (!cls.IsNull()); | |
| intptr_t num_fields = 0; | |
| for (intptr_t i = classes.length() - 1; i >= 0; --i) { | |
| field_array ^= classes[i]->fields(); | |
| if (!field_array.IsNull()) { | |
| for (intptr_t j = 0; j < field_array.Length(); ++j) { | |
| field ^= field_array.At(j); | |
| if (!field.is_static()) { | |
| ++num_fields; | |
| } | |
| } | |
| } | |
| } | |
| jsobj.AddProperty("length", num_fields); | |
| } | |
| void Instance::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void AbstractType::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| UNREACHABLE(); | |
| } | |
| void AbstractType::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const { | |
| UNREACHABLE(); | |
| } | |
| void Type::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref, /*include_id=*/false); | |
| jsobj.AddProperty("kind", "Type"); | |
| const Class& type_cls = Class::Handle(type_class()); | |
| if (type_cls.DeclarationType() == ptr()) { | |
| intptr_t cid = type_cls.id(); | |
| jsobj.AddFixedServiceId("classes/%" Pd "/types/%d", cid, 0); | |
| } else { | |
| jsobj.AddServiceId(*this); | |
| } | |
| jsobj.AddProperty("typeClass", type_cls); | |
| const String& user_name = String::Handle(UserVisibleName()); | |
| const String& vm_name = String::Handle(Name()); | |
| AddNameProperties(&jsobj, user_name.ToCString(), vm_name.ToCString()); | |
| if (ref) { | |
| return; | |
| } | |
| const TypeArguments& typeArgs = TypeArguments::Handle(arguments()); | |
| if (!typeArgs.IsNull()) { | |
| jsobj.AddProperty("typeArguments", typeArgs); | |
| } | |
| } | |
| void Type::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const {} | |
| void FunctionType::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "FunctionType"); | |
| AbstractType& type = AbstractType::Handle(result_type()); | |
| jsobj.AddProperty("returnType", type); | |
| const int type_params_count = NumTypeParameters(); | |
| if (type_params_count > 0) { | |
| JSONArray arr(&jsobj, "typeParameters"); | |
| TypeParameter& type_param = TypeParameter::Handle(); | |
| for (intptr_t i = 0; i < type_params_count; ++i) { | |
| type_param = TypeParameterAt(i); | |
| arr.AddValue(type_param); | |
| } | |
| } | |
| { | |
| JSONArray jsarr(&jsobj, "parameters"); | |
| String& name = String::Handle(); | |
| const intptr_t param_count = NumParameters(); | |
| const intptr_t fixed_param_count = num_fixed_parameters(); | |
| const bool has_named = HasOptionalNamedParameters(); | |
| for (intptr_t i = 0; i < param_count; ++i) { | |
| JSONObject param(&jsarr); | |
| type = ParameterTypeAt(i); | |
| param.AddProperty("parameterType", type); | |
| bool fixed = i < fixed_param_count; | |
| param.AddProperty("fixed", fixed); | |
| if (!fixed && has_named) { | |
| name = ParameterNameAt(i); | |
| param.AddProperty("name", name.ToCString()); | |
| param.AddProperty("required", IsRequiredAt(i)); | |
| } | |
| } | |
| } | |
| } | |
| void FunctionType::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void RecordType::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "RecordType"); | |
| if (ref) { | |
| return; | |
| } | |
| { | |
| JSONArray jsarr(&jsobj, "fields"); | |
| String& name = String::Handle(); | |
| AbstractType& type = AbstractType::Handle(); | |
| const intptr_t num_fields = NumFields(); | |
| const Array& field_names = Array::Handle(GetFieldNames(Thread::Current())); | |
| const intptr_t num_positional_fields = num_fields - field_names.Length(); | |
| for (intptr_t index = 0; index < num_fields; ++index) { | |
| JSONObject jsfield(&jsarr); | |
| if (index < num_positional_fields) { | |
| jsfield.AddProperty("name", index + 1); | |
| } else { | |
| name ^= field_names.At(index - num_positional_fields); | |
| jsfield.AddProperty("name", name.ToCString()); | |
| } | |
| type = FieldTypeAt(index); | |
| jsfield.AddProperty("value", type); | |
| } | |
| } | |
| } | |
| void RecordType::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void TypeParameter::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "TypeParameter"); | |
| const String& user_name = String::Handle(UserVisibleName()); | |
| const String& vm_name = String::Handle(Name()); | |
| AddNameProperties(&jsobj, user_name.ToCString(), vm_name.ToCString()); | |
| // TODO(regis): parameterizedClass is meaningless and always null. | |
| jsobj.AddProperty("parameterizedClass", Object::null_class()); | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddProperty("parameterIndex", index()); | |
| const AbstractType& upper_bound = AbstractType::Handle(bound()); | |
| jsobj.AddProperty("bound", upper_bound); | |
| } | |
| void TypeParameter::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Number::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| UNREACHABLE(); | |
| } | |
| void Number::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const { | |
| UNREACHABLE(); | |
| } | |
| void Integer::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "Int"); | |
| jsobj.AddProperty("valueAsString", ToCString()); | |
| } | |
| void Integer::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Smi::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref, /*include_id=*/false); | |
| jsobj.AddProperty("kind", "Int"); | |
| jsobj.AddFixedServiceId("objects/int-%" Pd "", Value()); | |
| jsobj.AddPropertyF("valueAsString", "%" Pd "", Value()); | |
| } | |
| void Smi::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const {} | |
| void Mint::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Integer::PrintJSONImpl(stream, ref); | |
| } | |
| void Mint::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const {} | |
| void Double::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "Double"); | |
| jsobj.AddProperty("valueAsString", ToCString()); | |
| } | |
| void Double::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void String::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "String"); | |
| jsobj.AddProperty("length", Length()); | |
| if (ref) { | |
| // String refs always truncate to a fixed count; | |
| const intptr_t kFixedCount = 128; | |
| if (jsobj.AddPropertyStr("valueAsString", *this, 0, kFixedCount)) { | |
| jsobj.AddProperty("count", kFixedCount); | |
| jsobj.AddProperty("valueAsStringIsTruncated", true); | |
| } | |
| return; | |
| } | |
| intptr_t offset; | |
| intptr_t count; | |
| stream->ComputeOffsetAndCount(Length(), &offset, &count); | |
| if (offset > 0) { | |
| jsobj.AddProperty("offset", offset); | |
| } | |
| if (count < Length()) { | |
| jsobj.AddProperty("count", count); | |
| } | |
| jsobj.AddPropertyStr("valueAsString", *this, offset, count); | |
| } | |
| void String::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Bool::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| const char* str = ToCString(); | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref, /*include_id=*/false); | |
| jsobj.AddProperty("kind", "Bool"); | |
| jsobj.AddFixedServiceId("objects/bool-%s", str); | |
| jsobj.AddPropertyF("valueAsString", "%s", str); | |
| } | |
| void Bool::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const {} | |
| void Array::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "List"); | |
| jsobj.AddProperty("length", Length()); | |
| if (ref) { | |
| return; | |
| } | |
| intptr_t offset; | |
| intptr_t count; | |
| stream->ComputeOffsetAndCount(Length(), &offset, &count); | |
| if (offset > 0) { | |
| jsobj.AddProperty("offset", offset); | |
| } | |
| if (count < Length()) { | |
| jsobj.AddProperty("count", count); | |
| } | |
| intptr_t limit = offset + count; | |
| ASSERT(limit <= Length()); | |
| { | |
| JSONArray jsarr(&jsobj, "elements"); | |
| Object& element = Object::Handle(); | |
| for (intptr_t index = offset; index < limit; index++) { | |
| element = At(index); | |
| jsarr.AddValue(element); | |
| } | |
| } | |
| } | |
| void Array::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const { | |
| } | |
| void GrowableObjectArray::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "List"); | |
| jsobj.AddProperty("length", Length()); | |
| if (ref) { | |
| return; | |
| } | |
| intptr_t offset; | |
| intptr_t count; | |
| stream->ComputeOffsetAndCount(Length(), &offset, &count); | |
| if (offset > 0) { | |
| jsobj.AddProperty("offset", offset); | |
| } | |
| if (count < Length()) { | |
| jsobj.AddProperty("count", count); | |
| } | |
| intptr_t limit = offset + count; | |
| ASSERT(limit <= Length()); | |
| { | |
| JSONArray jsarr(&jsobj, "elements"); | |
| Object& element = Object::Handle(); | |
| for (intptr_t index = offset; index < limit; index++) { | |
| element = At(index); | |
| jsarr.AddValue(element); | |
| } | |
| } | |
| } | |
| void GrowableObjectArray::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Map::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "Map"); | |
| jsobj.AddProperty("length", Length()); | |
| if (ref) { | |
| return; | |
| } | |
| intptr_t offset; | |
| intptr_t count; | |
| stream->ComputeOffsetAndCount(Length(), &offset, &count); | |
| if (offset > 0) { | |
| jsobj.AddProperty("offset", offset); | |
| } | |
| if (count < Length()) { | |
| jsobj.AddProperty("count", count); | |
| } | |
| intptr_t limit = offset + count; | |
| ASSERT(limit <= Length()); | |
| { | |
| JSONArray jsarr(&jsobj, "associations"); | |
| Object& object = Object::Handle(); | |
| Map::Iterator iterator(*this); | |
| int i = 0; | |
| while (iterator.MoveNext() && i < limit) { | |
| if (i >= offset) { | |
| JSONObject jsassoc(&jsarr); | |
| object = iterator.CurrentKey(); | |
| jsassoc.AddProperty("key", object); | |
| object = iterator.CurrentValue(); | |
| jsassoc.AddProperty("value", object); | |
| } | |
| i++; | |
| } | |
| } | |
| } | |
| void Map::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const {} | |
| void Set::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "Set"); | |
| jsobj.AddProperty("length", Length()); | |
| if (ref) { | |
| return; | |
| } | |
| intptr_t offset; | |
| intptr_t count; | |
| stream->ComputeOffsetAndCount(Length(), &offset, &count); | |
| if (offset > 0) { | |
| jsobj.AddProperty("offset", offset); | |
| } | |
| if (count < Length()) { | |
| jsobj.AddProperty("count", count); | |
| } | |
| intptr_t limit = offset + count; | |
| ASSERT(limit <= Length()); | |
| { | |
| JSONArray jsarr(&jsobj, "elements"); | |
| Object& object = Object::Handle(); | |
| Set::Iterator iterator(*this); | |
| int i = 0; | |
| while (iterator.MoveNext() && i < limit) { | |
| if (i >= offset) { | |
| object = iterator.CurrentKey(); | |
| jsarr.AddValue(object); | |
| } | |
| i++; | |
| } | |
| } | |
| } | |
| void Set::PrintImplementationFieldsImpl(const JSONArray& jsarr_fields) const {} | |
| void Float32x4::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "Float32x4"); | |
| jsobj.AddProperty("valueAsString", ToCString()); | |
| } | |
| void Float32x4::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Int32x4::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "Int32x4"); | |
| jsobj.AddProperty("valueAsString", ToCString()); | |
| } | |
| void Int32x4::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Float64x2::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "Float64x2"); | |
| jsobj.AddProperty("valueAsString", ToCString()); | |
| } | |
| void Float64x2::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void TypedDataBase::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| UNREACHABLE(); | |
| } | |
| void TypedDataBase::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const { | |
| UNREACHABLE(); | |
| } | |
| void TypedData::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| const Class& cls = Class::Handle(clazz()); | |
| const char* kind = cls.UserVisibleNameCString(); | |
| jsobj.AddProperty("kind", kind); | |
| jsobj.AddProperty("length", Length()); | |
| if (ref) { | |
| return; | |
| } | |
| intptr_t offset; | |
| intptr_t count; | |
| stream->ComputeOffsetAndCount(Length(), &offset, &count); | |
| if (offset > 0) { | |
| jsobj.AddProperty("offset", offset); | |
| } | |
| if (count < Length()) { | |
| jsobj.AddProperty("count", count); | |
| } | |
| if (count == 0) { | |
| jsobj.AddProperty("bytes", ""); | |
| } else { | |
| NoSafepointScope no_safepoint; | |
| jsobj.AddPropertyBase64("bytes", | |
| reinterpret_cast<const uint8_t*>( | |
| DataAddr(offset * ElementSizeInBytes())), | |
| count * ElementSizeInBytes()); | |
| } | |
| } | |
| void TypedData::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void TypedDataView::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Instance::PrintJSONImpl(stream, ref); | |
| } | |
| void TypedDataView::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void ExternalTypedData::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| const Class& cls = Class::Handle(clazz()); | |
| const char* kind = cls.UserVisibleNameCString(); | |
| jsobj.AddProperty("kind", kind); | |
| jsobj.AddProperty("length", Length()); | |
| if (ref) { | |
| return; | |
| } | |
| intptr_t offset; | |
| intptr_t count; | |
| stream->ComputeOffsetAndCount(Length(), &offset, &count); | |
| if (offset > 0) { | |
| jsobj.AddProperty("offset", offset); | |
| } | |
| if (count < Length()) { | |
| jsobj.AddProperty("count", count); | |
| } | |
| if (count == 0) { | |
| jsobj.AddProperty("bytes", ""); | |
| } else { | |
| NoSafepointScope no_safepoint; | |
| jsobj.AddPropertyBase64("bytes", | |
| reinterpret_cast<const uint8_t*>( | |
| DataAddr(offset * ElementSizeInBytes())), | |
| count * ElementSizeInBytes()); | |
| } | |
| } | |
| void ExternalTypedData::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Pointer::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "Pointer"); | |
| jsobj.AddPropertyF("valueAsString", "0x%" Px "", NativeAddress()); | |
| } | |
| void Pointer::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void DynamicLibrary::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Instance::PrintJSONImpl(stream, ref); | |
| } | |
| void DynamicLibrary::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Capability::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Instance::PrintJSONImpl(stream, ref); | |
| } | |
| void Capability::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void ReceivePort::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject obj(stream); | |
| Instance::PrintSharedInstanceJSON(&obj, ref); | |
| const StackTrace& allocation_location_ = | |
| StackTrace::Handle(allocation_location()); | |
| const String& debug_name_ = String::Handle(debug_name()); | |
| obj.AddProperty("kind", "ReceivePort"); | |
| obj.AddProperty64("portId", Id()); | |
| obj.AddProperty("debugName", debug_name_.ToCString()); | |
| obj.AddProperty("allocationLocation", allocation_location_); | |
| } | |
| void ReceivePort::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void SendPort::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Instance::PrintJSONImpl(stream, ref); | |
| } | |
| void SendPort::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void TransferableTypedData::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Instance::PrintJSONImpl(stream, ref); | |
| } | |
| void TransferableTypedData::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void ClosureData::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Object::PrintJSONImpl(stream, ref); | |
| } | |
| void ClosureData::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Closure::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "Closure"); | |
| const auto& func = Function::Handle(function()); | |
| jsobj.AddProperty("closureFunction", func); | |
| if (!func.IsImplicitClosureFunction()) { | |
| jsobj.AddProperty("closureContext", Context::Handle(GetContext())); | |
| } else { | |
| jsobj.AddProperty("closureContext", Object::null_object()); | |
| } | |
| if (func.IsImplicitInstanceClosureFunction()) { | |
| jsobj.AddProperty("closureReceiver", | |
| Object::Handle(GetImplicitClosureReceiver())); | |
| } else { | |
| jsobj.AddProperty("closureReceiver", Object::null_object()); | |
| } | |
| if (ref) { | |
| return; | |
| } | |
| Debugger* debugger = Isolate::Current()->debugger(); | |
| Breakpoint* bpt = debugger->BreakpointAtActivation(*this); | |
| if (bpt != nullptr) { | |
| jsobj.AddProperty("_activationBreakpoint", bpt); | |
| } | |
| } | |
| void Closure::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void Record::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "Record"); | |
| const intptr_t num_fields = this->num_fields(); | |
| jsobj.AddProperty("length", num_fields); | |
| if (ref) { | |
| return; | |
| } | |
| { | |
| JSONArray jsarr(&jsobj, "fields"); | |
| String& name = String::Handle(); | |
| Object& value = Object::Handle(); | |
| const Array& field_names = Array::Handle(GetFieldNames(Thread::Current())); | |
| const intptr_t num_positional_fields = num_fields - field_names.Length(); | |
| for (intptr_t index = 0; index < num_fields; ++index) { | |
| JSONObject jsfield(&jsarr); | |
| if (index < num_positional_fields) { | |
| jsfield.AddProperty("name", index + 1); | |
| } else { | |
| name ^= field_names.At(index - num_positional_fields); | |
| jsfield.AddProperty("name", name.ToCString()); | |
| } | |
| value = FieldAt(index); | |
| jsfield.AddProperty("value", value); | |
| } | |
| } | |
| } | |
| void Record::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void StackTrace::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "StackTrace"); | |
| jsobj.AddProperty("valueAsString", ToCString()); | |
| } | |
| void StackTrace::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void RegExp::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "RegExp"); | |
| jsobj.AddProperty("pattern", String::Handle(pattern())); | |
| if (ref) { | |
| return; | |
| } | |
| jsobj.AddProperty("isCaseSensitive", !IsIgnoreCase(flags())); | |
| jsobj.AddProperty("isMultiLine", IsMultiline(flags())); | |
| jsobj.AddProperty("isUnicode", IsUnicode(flags())); | |
| jsobj.AddProperty("isDotAll", IsDotAll(flags())); | |
| TypedData& bc = TypedData::Handle(); | |
| bc = bytecode(/*is_one_byte=*/true, /*sticky=*/false); | |
| jsobj.AddProperty("_oneByteBytecode", bc); | |
| bc = bytecode(/*is_one_byte=*/false, /*sticky=*/false); | |
| jsobj.AddProperty("_twoByteBytecode", bc); | |
| bc = bytecode(/*is_one_byte=*/true, /*sticky=*/true); | |
| jsobj.AddProperty("_oneByteBytecodeSticky", bc); | |
| bc = bytecode(/*is_one_byte=*/false, /*sticky=*/true); | |
| jsobj.AddProperty("_twoByteBytecodeSticky", bc); | |
| } | |
| void RegExp::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void WeakProperty::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "WeakProperty"); | |
| if (ref) { | |
| return; | |
| } | |
| const Object& key_handle = Object::Handle(key()); | |
| jsobj.AddProperty("propertyKey", key_handle); | |
| const Object& value_handle = Object::Handle(value()); | |
| jsobj.AddProperty("propertyValue", value_handle); | |
| } | |
| void WeakProperty::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void WeakReference::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "WeakReference"); | |
| if (ref) { | |
| return; | |
| } | |
| const Object& target_handle = Object::Handle(target()); | |
| jsobj.AddProperty("target", target_handle); | |
| } | |
| void WeakReference::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void FinalizerBase::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| UNREACHABLE(); | |
| } | |
| void FinalizerBase::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const { | |
| UNREACHABLE(); | |
| } | |
| void Finalizer::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "Finalizer"); | |
| if (ref) { | |
| return; | |
| } | |
| Object& object = Object::Handle(); | |
| object = callback(); | |
| jsobj.AddProperty("callback", object); | |
| object = all_entries(); | |
| jsobj.AddProperty("allEntries", object); | |
| object = entries_collected(); | |
| jsobj.AddProperty("_entriesCollected", object); | |
| } | |
| void Finalizer::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void NativeFinalizer::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "NativeFinalizer"); | |
| if (ref) { | |
| return; | |
| } | |
| Object& object = Object::Handle(); | |
| object = callback(); | |
| jsobj.AddProperty("callbackAddress", object); | |
| object = all_entries(); | |
| jsobj.AddProperty("allEntries", object); | |
| object = entries_collected(); | |
| jsobj.AddProperty("_entriesCollected", object); | |
| } | |
| void NativeFinalizer::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void FinalizerEntry::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "FinalizerEntry"); | |
| if (ref) { | |
| return; | |
| } | |
| Object& object = Object::Handle(); | |
| object = value(); | |
| jsobj.AddProperty("value", object); | |
| object = detach(); | |
| jsobj.AddProperty("detach", object); | |
| object = token(); | |
| jsobj.AddProperty("token", object); | |
| object = finalizer(); | |
| jsobj.AddProperty("_finalizer", object); | |
| object = next(); | |
| jsobj.AddProperty("_next", object); | |
| } | |
| void FinalizerEntry::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void MirrorReference::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "MirrorReference"); | |
| if (ref) { | |
| return; | |
| } | |
| const Object& referent_handle = Object::Handle(referent()); | |
| jsobj.AddProperty("mirrorReferent", referent_handle); | |
| } | |
| void MirrorReference::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| JSONObject jsobj(stream); | |
| PrintSharedInstanceJSON(&jsobj, ref); | |
| jsobj.AddProperty("kind", "UserTag"); | |
| String& tag_label = String::Handle(label()); | |
| jsobj.AddProperty("label", tag_label.ToCString()); | |
| } | |
| void UserTag::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void FutureOr::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Instance::PrintJSONImpl(stream, ref); | |
| } | |
| void FutureOr::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| void SuspendState::PrintJSONImpl(JSONStream* stream, bool ref) const { | |
| Instance::PrintJSONImpl(stream, ref); | |
| } | |
| void SuspendState::PrintImplementationFieldsImpl( | |
| const JSONArray& jsarr_fields) const {} | |
| #endif | |
| } // namespace dart |