* Copyright 2012-2015, Rene Gollent, rene@gollent.com
* Distributed under the terms of the MIT License.
*/
#include "BListValueNode.h"
#include <new>
#include <AutoDeleter.h>
#include "AddressValueNode.h"
#include "Architecture.h"
#include "StringValue.h"
#include "TeamTypeInformation.h"
#include "Tracing.h"
#include "Type.h"
#include "TypeLookupConstraints.h"
#include "ValueLoader.h"
#include "ValueLocation.h"
#include "ValueNodeContainer.h"
static const int64 kMaxArrayElementCount = 20;
class BListValueNode::BListElementNodeChild : public ValueNodeChild {
public:
BListElementNodeChild(BListValueNode* parent,
int64 elementIndex, Type* type);
virtual ~BListElementNodeChild();
virtual const BString& Name() const { return fName; };
virtual Type* GetType() const { return fType; };
virtual ValueNode* Parent() const { return fParent; };
virtual status_t ResolveLocation(ValueLoader* valueLoader,
ValueLocation*& _location);
private:
Type* fType;
BListValueNode* fParent;
int64 fElementIndex;
BString fName;
};
BListValueNode::BListElementNodeChild::BListElementNodeChild(
BListValueNode* parent, int64 elementIndex, Type* type)
:
ValueNodeChild(),
fType(type),
fParent(parent),
fElementIndex(elementIndex),
fName()
{
fType->AcquireReference();
fParent->AcquireReference();
fName.SetToFormat("[%" B_PRId64 "]", fElementIndex);
}
BListValueNode::BListElementNodeChild::~BListElementNodeChild()
{
fType->ReleaseReference();
fParent->ReleaseReference();
}
status_t
BListValueNode::BListElementNodeChild::ResolveLocation(
ValueLoader* valueLoader, ValueLocation*& _location)
{
uint8 addressSize = valueLoader->GetArchitecture()->AddressSize();
ValueLocation* location = new(std::nothrow) ValueLocation();
if (location == NULL)
return B_NO_MEMORY;
uint64 listAddress = fParent->fDataLocation.ToUInt64();
listAddress += fElementIndex * addressSize;
ValuePieceLocation piece;
piece.SetToMemory(listAddress);
piece.SetSize(addressSize);
location->AddPiece(piece);
_location = location;
return B_OK;
}
class BListValueNode::BListItemCountNodeChild : public ValueNodeChild {
public:
BListItemCountNodeChild(BVariant location,
BListValueNode* parent, Type* type);
virtual ~BListItemCountNodeChild();
virtual const BString& Name() const { return fName; };
virtual Type* GetType() const { return fType; };
virtual ValueNode* Parent() const { return fParent; };
virtual status_t ResolveLocation(ValueLoader* valueLoader,
ValueLocation*& _location);
private:
Type* fType;
BListValueNode* fParent;
BVariant fLocation;
BString fName;
};
BListValueNode::BListItemCountNodeChild::BListItemCountNodeChild(
BVariant location, BListValueNode* parent, Type* type)
:
ValueNodeChild(),
fType(type),
fParent(parent),
fLocation(location),
fName("Capacity")
{
fType->AcquireReference();
fParent->AcquireReference();
}
BListValueNode::BListItemCountNodeChild::~BListItemCountNodeChild()
{
fType->ReleaseReference();
fParent->ReleaseReference();
}
status_t
BListValueNode::BListItemCountNodeChild::ResolveLocation(
ValueLoader* valueLoader, ValueLocation*& _location)
{
ValueLocation* location = new(std::nothrow) ValueLocation();
if (location == NULL)
return B_NO_MEMORY;
ValuePieceLocation piece;
piece.SetToMemory(fLocation.ToUInt64());
piece.SetSize(sizeof(int32));
location->AddPiece(piece);
_location = location;
return B_OK;
}
BListValueNode::BListValueNode(ValueNodeChild* nodeChild,
Type* type)
:
ValueNode(nodeChild),
fType(type),
fItemCountType(NULL),
fItemCount(0),
fCountChildCreated(false)
{
fType->AcquireReference();
}
BListValueNode::~BListValueNode()
{
fType->ReleaseReference();
for (int32 i = 0; i < fChildren.CountItems(); i++)
fChildren.ItemAt(i)->ReleaseReference();
if (fItemCountType != NULL)
fItemCountType->ReleaseReference();
}
Type*
BListValueNode::GetType() const
{
return fType;
}
status_t
BListValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader,
ValueLocation*& _location, Value*& _value)
{
ValueLocation* location = NodeChild()->Location();
if (location == NULL)
return B_BAD_VALUE;
type_code valueType;
if (valueLoader->GetArchitecture()->AddressSize() == 4) {
valueType = B_UINT32_TYPE;
TRACE_LOCALS(" -> 32 bit\n");
} else {
valueType = B_UINT64_TYPE;
TRACE_LOCALS(" -> 64 bit\n");
}
status_t error = B_OK;
ValueLocation* memberLocation = NULL;
CompoundType* baseType = dynamic_cast<CompoundType*>(fType);
if (baseType->CountTemplateParameters() != 0) {
if (baseType->CountBaseTypes() == 0)
return B_BAD_DATA;
baseType = dynamic_cast<CompoundType*>(baseType->BaseTypeAt(0)
->GetType());
if (baseType == NULL || baseType->Name() != "_PointerList_")
return B_BAD_DATA;
if (baseType->CountBaseTypes() == 0)
return B_BAD_DATA;
baseType = dynamic_cast<CompoundType*>(baseType->BaseTypeAt(0)
->GetType());
if (baseType == NULL || baseType->Name() != "BList")
return B_BAD_DATA;
}
for (int32 i = 0; i < baseType->CountDataMembers(); i++) {
DataMember* member = baseType->DataMemberAt(i);
if (strcmp(member->Name(), "fObjectList") == 0) {
error = baseType->ResolveDataMemberLocation(member,
*location, memberLocation);
BReference<ValueLocation> locationRef(memberLocation, true);
if (error != B_OK) {
TRACE_LOCALS(
"BListValueNode::ResolvedLocationAndValue(): "
"failed to resolve location of header member: %s\n",
strerror(error));
return error;
}
error = valueLoader->LoadValue(memberLocation, valueType,
false, fDataLocation);
if (error != B_OK)
return error;
} else if (strcmp(member->Name(), "fItemCount") == 0) {
error = baseType->ResolveDataMemberLocation(member,
*location, memberLocation);
BReference<ValueLocation> locationRef(memberLocation, true);
if (error != B_OK) {
TRACE_LOCALS(
"BListValueNode::ResolvedLocationAndValue(): "
"failed to resolve location of header member: %s\n",
strerror(error));
return error;
}
fItemCountType = member->GetType();
fItemCountType->AcquireReference();
fItemCountLocation = memberLocation->PieceAt(0).address;
BVariant listSize;
error = valueLoader->LoadValue(memberLocation, B_INT32_TYPE,
false, listSize);
if (error != B_OK)
return error;
fItemCount = listSize.ToInt32();
TRACE_LOCALS(
"BListValueNode::ResolvedLocationAndValue(): "
"detected list size %" B_PRId32 "\n",
fItemCount);
}
memberLocation = NULL;
}
location->AcquireReference();
_location = location;
_value = NULL;
return B_OK;
}
status_t
BListValueNode::CreateChildren(TeamTypeInformation* info)
{
return CreateChildrenInRange(info, 0, kMaxArrayElementCount);
}
int32
BListValueNode::CountChildren() const
{
return fChildren.CountItems();
}
ValueNodeChild*
BListValueNode::ChildAt(int32 index) const
{
return fChildren.ItemAt(index);
}
bool
BListValueNode::IsRangedContainer() const
{
return true;
}
bool
BListValueNode::IsContainerRangeFixed() const
{
return true;
}
void
BListValueNode::ClearChildren()
{
fChildren.MakeEmpty();
fCountChildCreated = false;
if (fContainer != NULL)
fContainer->NotifyValueNodeChildrenDeleted(this);
}
status_t
BListValueNode::CreateChildrenInRange(TeamTypeInformation* info,
int32 lowIndex, int32 highIndex)
{
if (fLocationResolutionState != B_OK)
return fLocationResolutionState;
if (lowIndex < 0)
lowIndex = 0;
if (highIndex >= fItemCount)
highIndex = fItemCount - 1;
if (!fCountChildCreated && fItemCountType != NULL) {
BListItemCountNodeChild* countChild = new(std::nothrow)
BListItemCountNodeChild(fItemCountLocation, this, fItemCountType);
if (countChild == NULL)
return B_NO_MEMORY;
fCountChildCreated = true;
countChild->SetContainer(fContainer);
fChildren.AddItem(countChild);
}
BReference<Type> addressTypeRef;
Type* type = NULL;
CompoundType* objectType = dynamic_cast<CompoundType*>(fType);
if (objectType->CountTemplateParameters() != 0) {
AddressType* addressType = NULL;
status_t result = objectType->TemplateParameterAt(0)->GetType()
->CreateDerivedAddressType(DERIVED_TYPE_POINTER, addressType);
if (result != B_OK)
return result;
type = addressType;
addressTypeRef.SetTo(type, true);
} else {
BString typeName;
TypeLookupConstraints constraints;
constraints.SetTypeKind(TYPE_ADDRESS);
constraints.SetBaseTypeName("void");
status_t result = info->LookupTypeByName(typeName, constraints,
type);
if (result != B_OK)
return result;
}
for (int32 i = lowIndex; i <= highIndex; i++)
{
BListElementNodeChild* child =
new(std::nothrow) BListElementNodeChild(this, i, type);
if (child == NULL)
return B_NO_MEMORY;
child->SetContainer(fContainer);
fChildren.AddItem(child);
}
fChildrenCreated = true;
if (fContainer != NULL)
fContainer->NotifyValueNodeChildrenCreated(this);
return B_OK;
}
status_t
BListValueNode::SupportedChildRange(int32& lowIndex, int32& highIndex) const
{
lowIndex = 0;
highIndex = fItemCount - 1;
return B_OK;
}