blob: 86f3fdf4fc632e29b3afbcbd3554202714573ced [file] [log] [blame]
// Copyright 2020 The Fuchsia 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/developer/shell/interpreter/src/value.h"
#include <cstdint>
#include <string>
#include "src/developer/shell/interpreter/src/interpreter.h"
#include "src/developer/shell/interpreter/src/schema.h"
namespace shell {
namespace interpreter {
String::String(Interpreter* interpreter, std::string_view value)
: ReferenceCounted(interpreter), value_(value) {
interpreter_->increment_string_count();
}
String::String(Interpreter* interpreter, std::string&& value)
: ReferenceCounted(interpreter), value_(std::move(value)) {
interpreter_->increment_string_count();
}
String::~String() { interpreter_->decrement_string_count(); }
Object::Object(Interpreter* interpreter, const std::shared_ptr<ObjectSchema> schema)
: ReferenceCounted(interpreter), schema_(schema) {
interpreter_->increment_object_count();
}
Object::~Object() {
interpreter_->decrement_object_count();
// Free all the applicative fields by assigning zero.
for (const auto& field : schema_->fields()) {
field->type()->SetData(reinterpret_cast<uint8_t*>(this) + field->offset(), 0,
/*free_old_value=*/true);
}
}
const std::shared_ptr<ObjectSchema> Object::schema() { return schema_; }
std::unique_ptr<Value> Object::GetField(const ObjectFieldSchema* field) const {
FX_DCHECK(field != nullptr) << "Invalid field pointer passed to getfield";
uint64_t offset = field->offset();
std::unique_ptr<Value> v = std::make_unique<Value>();
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this) + offset;
// TODO: We need to factorize this code with Type::LoadVariable. This probably involves
// merging ValueKind and TypeKind.
switch (field->type()->Kind()) {
case Type::TypeKind::kInt8:
v->SetInt8(*reinterpret_cast<const int8_t*>(ptr));
break;
case Type::TypeKind::kUint8:
v->SetUint8(*reinterpret_cast<const uint8_t*>(ptr));
break;
case Type::TypeKind::kInt16:
v->SetInt16(*reinterpret_cast<const int16_t*>(ptr));
break;
case Type::TypeKind::kUint16:
v->SetUint16(*reinterpret_cast<const uint16_t*>(ptr));
break;
case Type::TypeKind::kInt32:
v->SetInt32(*reinterpret_cast<const int32_t*>(ptr));
break;
case Type::TypeKind::kUint32:
v->SetUint32(*reinterpret_cast<const uint32_t*>(ptr));
break;
case Type::TypeKind::kInt64:
case Type::TypeKind::kInteger:
v->SetInt64(*reinterpret_cast<const int64_t*>(ptr));
break;
case Type::TypeKind::kUint64:
v->SetUint64(*reinterpret_cast<const uint64_t*>(ptr));
break;
case Type::TypeKind::kString:
v->SetString(*reinterpret_cast<String* const*>(ptr));
break;
case Type::TypeKind::kObject:
v->SetObject(*reinterpret_cast<Object* const*>(ptr));
break;
default:
FX_NOTREACHED() << "Unknown type in getfield";
// Assert unknown type.
break;
}
return v;
}
void Object::SetField(const ObjectFieldSchema* field, uint64_t value) {
field->type()->SetData(reinterpret_cast<uint8_t*>(this) + field->offset(), value,
/*free_old_value=*/false);
}
void Object::Free() {
// Call the destructor.
this->~Object();
// Deallocate the object using the same mechanism used to allocate it.
delete[] reinterpret_cast<uint8_t*>(this);
}
void Value::Set(const Value& value) {
// For types which need to take a reference, we take the reference before we release the old
// value. This way, we don't end with a reference to a destroyed value if the user assigns a
// value to itself.
switch (value.type_) {
case ValueType::kUndef:
Release();
break;
case ValueType::kInt8:
Release();
int8_value_ = value.int8_value_;
break;
case ValueType::kUint8:
Release();
uint8_value_ = value.uint8_value_;
break;
case ValueType::kInt16:
Release();
int16_value_ = value.int16_value_;
break;
case ValueType::kUint16:
Release();
uint16_value_ = value.uint16_value_;
break;
case ValueType::kInt32:
Release();
int32_value_ = value.int32_value_;
break;
case ValueType::kUint32:
Release();
uint32_value_ = value.uint32_value_;
break;
case ValueType::kInt64:
Release();
int64_value_ = value.int64_value_;
break;
case ValueType::kUint64:
Release();
uint64_value_ = value.uint64_value_;
break;
case ValueType::kString: {
String* string = value.string_->Use();
Release();
string_ = string;
break;
}
case ValueType::kObject: {
Object* object = value.object_->Use();
Release();
object_ = object;
break;
}
}
type_ = value.type_;
}
void Value::Release() {
switch (type_) {
case ValueType::kUndef:
case ValueType::kInt8:
case ValueType::kUint8:
case ValueType::kInt16:
case ValueType::kUint16:
case ValueType::kInt32:
case ValueType::kUint32:
case ValueType::kInt64:
case ValueType::kUint64:
break;
case ValueType::kString:
string_->Release();
break;
case ValueType::kObject:
object_->Release();
break;
}
}
} // namespace interpreter
} // namespace shell