summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2018-02-11 21:57:10 +0800
committerJohn Hodge <tpg@mutabah.net>2018-02-11 21:57:10 +0800
commita3a0c6437302c60bd6f521fc11e30c0a16bd79fc (patch)
tree83b536f1d5b170a88417015ec0a7f378ab6ea4c4 /tools
parent14fea32f414df2d1e0b8e2669c8fe13132210ae9 (diff)
downloadmrust-a3a0c6437302c60bd6f521fc11e30c0a16bd79fc.tar.gz
Standalone MIRI - Implementation sprint, statics in process.
Diffstat (limited to 'tools')
-rw-r--r--tools/standalone_miri/hir_sim.cpp26
-rw-r--r--tools/standalone_miri/hir_sim.hpp1
-rw-r--r--tools/standalone_miri/main.cpp156
-rw-r--r--tools/standalone_miri/module_tree.cpp61
-rw-r--r--tools/standalone_miri/module_tree.hpp9
-rw-r--r--tools/standalone_miri/value.cpp183
-rw-r--r--tools/standalone_miri/value.hpp72
7 files changed, 478 insertions, 30 deletions
diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp
index 0010e202..7fccc806 100644
--- a/tools/standalone_miri/hir_sim.cpp
+++ b/tools/standalone_miri/hir_sim.cpp
@@ -6,6 +6,8 @@
#include "hir_sim.hpp"
#include "module_tree.hpp"
+const size_t POINTER_SIZE = 8;
+
//::HIR::Path::Path(::HIR::SimplePath sp)
//{
//}
@@ -22,6 +24,7 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
case RawType::Composite:
return this->composite_type->size;
case RawType::Unreachable:
+ case RawType::TraitObject:
case RawType::Str:
throw "Invalid";
case RawType::U8: case RawType::I8:
@@ -35,6 +38,16 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
case RawType::U128: case RawType::I128:
return 16;
+ case RawType::Bool:
+ return 1;
+ case RawType::Char:
+ return 4;
+
+ case RawType::F32:
+ return 4;
+ case RawType::F64:
+ return 8;
+
case RawType::Function: // This should probably be invalid?
case RawType::USize: case RawType::ISize:
return POINTER_SIZE;
@@ -52,7 +65,10 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
{
// Need to look up the metadata type for the actual type
if( this->inner_type == RawType::Composite )
- throw "TODO";
+ {
+ ::std::cerr << "TODO: Check metadata type for pointer " << *this << ", assuming none" << ::std::endl;
+ return POINTER_SIZE;
+ }
else if( this->inner_type == RawType::Str )
return POINTER_SIZE*2;
else if( this->inner_type == RawType::TraitObject )
@@ -175,6 +191,12 @@ namespace HIR {
case RawType::Unreachable:
os << "!";
break;
+ case RawType::Function:
+ os << "function_?";
+ break;
+ case RawType::TraitObject:
+ os << "traitobject_?";
+ break;
case RawType::Bool: os << "bool"; break;
case RawType::Char: os << "char"; break;
case RawType::Str: os << "str"; break;
@@ -191,6 +213,8 @@ namespace HIR {
case RawType::I128: os << "i128"; break;
case RawType::USize: os << "usize"; break;
case RawType::ISize: os << "isize"; break;
+ case RawType::F32: os << "f32"; break;
+ case RawType::F64: os << "f64"; break;
}
for(auto it = x.wrappers.rbegin(); it != x.wrappers.rend(); ++it)
{
diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp
index 1303f077..96887536 100644
--- a/tools/standalone_miri/hir_sim.hpp
+++ b/tools/standalone_miri/hir_sim.hpp
@@ -82,6 +82,7 @@ namespace HIR {
/// Definition of a type
struct TypeRef
{
+ // Top to bottom list of wrappers (first entry is the outermost wrapper)
::std::vector<TypeWrapper> wrappers;
RawType inner_type = RawType::Unit;
const DataType* composite_type = nullptr;
diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp
index a6a58a91..c7069ed2 100644
--- a/tools/standalone_miri/main.cpp
+++ b/tools/standalone_miri/main.cpp
@@ -7,8 +7,6 @@
#include <algorithm>
#include <iomanip>
-#pragma warning( error : 4061)
-
struct ProgramOptions
{
::std::string infile;
@@ -16,7 +14,7 @@ struct ProgramOptions
int parse(int argc, const char* argv[]);
};
-Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args);
+Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args);
int main(int argc, const char* argv[])
{
@@ -31,15 +29,32 @@ int main(int argc, const char* argv[])
tree.load_file(opts.infile);
- auto rv = MIRI_Invoke(tree, tree.find_lang_item("start"), {});
+ auto val_argc = Value( ::HIR::TypeRef{RawType::I32} );
+ ::HIR::TypeRef argv_ty { RawType::I8 };
+ argv_ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, 0 });
+ argv_ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, 0 });
+ auto val_argv = Value(argv_ty);
+ val_argc.write_bytes(0, "\0\0\0", 4);
+ val_argv.write_bytes(0, "\0\0\0\0\0\0\0", argv_ty.get_size());
+
+ ::std::vector<Value> args;
+ args.push_back(::std::move(val_argc));
+ args.push_back(::std::move(val_argv));
+ auto rv = MIRI_Invoke( tree, tree.find_lang_item("start"), ::std::move(args) );
::std::cout << rv << ::std::endl;
return 0;
}
-Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args)
+Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args)
{
+ //TRACE_FUNCTION_FR(path,path)
const auto& fcn = modtree.get_function(path);
+ for(size_t i = 0; i < args.size(); i ++)
+ {
+ //DEBUG(a);
+ ::std::cout << "Argument(" << i << ") = " << args[i] << ::std::endl;
+ }
::std::vector<bool> drop_flags = fcn.m_mir.drop_flags;
::std::vector<Value> locals; locals.reserve( fcn.m_mir.locals.size() );
@@ -52,12 +67,14 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val
struct State
{
+ ModuleTree& modtree;
const Function& fcn;
Value ret;
::std::vector<Value> args;
::std::vector<Value> locals;
- State(const Function& fcn, ::std::vector<Value> args):
+ State(ModuleTree& modtree, const Function& fcn, ::std::vector<Value> args):
+ modtree(modtree),
fcn(fcn),
ret(fcn.ret_ty),
args(::std::move(args))
@@ -73,6 +90,7 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val
{
switch(lv.tag())
{
+ case ::MIR::LValue::TAGDEAD: throw "";
TU_ARM(lv, Return, _e) {
ofs = 0;
ty = fcn.ret_ty;
@@ -88,6 +106,9 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val
ty = fcn.args.at(e.idx);
return args.at(e.idx);
} break;
+ TU_ARM(lv, Static, e) {
+ return modtree.get_static(e);
+ } break;
TU_ARM(lv, Index, e) {
auto idx = read_lvalue(*e.idx).as_usize();
::HIR::TypeRef array_ty;
@@ -118,6 +139,23 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val
ofs += inner_ofs;
return base_val;
}
+ TU_ARM(lv, Downcast, e) {
+ ::HIR::TypeRef composite_ty;
+ auto& base_val = get_value_type_and_ofs(*e.val, ofs, composite_ty);
+
+ size_t inner_ofs;
+ ty = composite_ty.get_field(e.variant_index, inner_ofs);
+ ::std::cerr << "TODO: Read from Downcast - " << lv << ::std::endl;
+ throw "TODO";
+ ofs += inner_ofs;
+ return base_val;
+ }
+ TU_ARM(lv, Deref, e) {
+ //auto addr = read_lvalue(*e.val);
+
+ ::std::cerr << "TODO: Read from deref - " << lv << ::std::endl;
+ throw "TODO";
+ } break;
}
throw "";
}
@@ -161,6 +199,7 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val
{
switch(c.tag())
{
+ case ::MIR::Constant::TAGDEAD: throw "";
TU_ARM(c, Int, ce) {
ty = ::HIR::TypeRef(ce.t);
Value val = Value(ty);
@@ -174,6 +213,42 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val
val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian
return val;
} break;
+ TU_ARM(c, Bool, ce) {
+ Value val = Value(::HIR::TypeRef { RawType::Bool });
+ val.write_bytes(0, &ce.v, 1);
+ return val;
+ } break;
+ TU_ARM(c, Float, ce) {
+ ty = ::HIR::TypeRef(ce.t);
+ Value val = Value(ty);
+ if( ce.t.raw_type == RawType::F64 ) {
+ val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian/format?
+ }
+ else if( ce.t.raw_type == RawType::F32 ) {
+ float v = static_cast<float>(ce.v);
+ val.write_bytes(0, &v, ::std::min(ty.get_size(), sizeof(v))); // TODO: Endian/format?
+ }
+ else {
+ throw ::std::runtime_error("BUG: Invalid type in Constant::Float");
+ }
+ return val;
+ } break;
+ TU_ARM(c, Const, ce) {
+ throw ::std::runtime_error("BUG: Constant::Const in mmir");
+ } break;
+ TU_ARM(c, Bytes, ce) {
+ throw ::std::runtime_error("TODO: Constant::Bytes");
+ } break;
+ TU_ARM(c, StaticString, ce) {
+ throw ::std::runtime_error("TODO: Constant::StaticString");
+ } break;
+ TU_ARM(c, ItemAddr, ce) {
+ // Create a value with a special backing allocation of zero size that references the specified item.
+ if( const auto* fn = modtree.get_function_opt(ce) ) {
+ return Value::new_fnptr(ce);
+ }
+ throw ::std::runtime_error("TODO: Constant::ItemAddr");
+ } break;
}
throw "";
}
@@ -186,6 +261,7 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val
{
switch(p.tag())
{
+ case ::MIR::Param::TAGDEAD: throw "";
TU_ARM(p, Constant, pe)
return const_to_value(pe, ty);
TU_ARM(p, LValue, pe)
@@ -198,7 +274,7 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val
::HIR::TypeRef ty;
return param_to_value(p, ty);
}
- } state { fcn, ::std::move(args) };
+ } state { modtree, fcn, ::std::move(args) };
size_t bb_idx = 0;
for(;;)
@@ -210,16 +286,38 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val
::std::cout << "BB" << bb_idx << "/" << (&stmt - bb.statements.data()) << ": " << stmt << ::std::endl;
switch(stmt.tag())
{
+ case ::MIR::Statement::TAGDEAD: throw "";
TU_ARM(stmt, Assign, se) {
Value val;
switch(se.src.tag())
{
+ case ::MIR::RValue::TAGDEAD: throw "";
TU_ARM(se.src, Use, re) {
state.write_lvalue(se.dst, state.read_lvalue(re));
} break;
TU_ARM(se.src, Constant, re) {
state.write_lvalue(se.dst, state.const_to_value(re));
} break;
+ TU_ARM(se.src, Borrow, re) {
+ ::HIR::TypeRef src_ty;
+ size_t ofs = 0;
+ Value& base_value = state.get_value_type_and_ofs(re.val, ofs, src_ty);
+ if( !base_value.allocation )
+ {
+ // TODO: Need to convert this value into an allocation version
+ ::std::cerr << "TODO: RValue::Borrow - " << se.src << " - convert to non-inline" << ::std::endl;
+ throw "TODO";
+ //base_value.to_allocation();
+ }
+ ofs += base_value.meta.indirect_meta.offset;
+ src_ty.wrappers.insert(src_ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, static_cast<size_t>(re.type) });
+ Value new_val = Value(src_ty);
+ // ^ Pointer value
+ new_val.allocation.alloc().relocations.push_back(Relocation { 0, base_value.allocation });
+ new_val.write_bytes(0, &ofs, src_ty.get_size());
+ ::std::cerr << "TODO: RValue::Borrow - " << se.src << ::std::endl;
+ throw "TODO";
+ } break;
TU_ARM(se.src, SizedArray, re) {
throw "TODO";
} break;
@@ -272,17 +370,61 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val
case ::MIR::Statement::TAG_SetDropFlag:
throw "TODO";
break;
+ case ::MIR::Statement::TAG_ScopeEnd:
+ throw "TODO";
+ break;
}
}
::std::cout << "BB" << bb_idx << "/TERM: " << bb.terminator << ::std::endl;
switch(bb.terminator.tag())
{
+ case ::MIR::Terminator::TAGDEAD: throw "";
+ TU_ARM(bb.terminator, Incomplete, _te)
+ throw ::std::runtime_error("BUG: Terminator::Incomplete hit");
+ TU_ARM(bb.terminator, Diverge, _te)
+ throw ::std::runtime_error("BUG: Terminator::Diverge hit");
+ TU_ARM(bb.terminator, Panic, _te)
+ throw ::std::runtime_error("TODO: Terminator::Panic");
TU_ARM(bb.terminator, Goto, te)
bb_idx = te;
continue;
TU_ARM(bb.terminator, Return, _te)
return state.ret;
+ TU_ARM(bb.terminator, If, _te)
+ throw ::std::runtime_error("TODO: Terminator::If");
+ TU_ARM(bb.terminator, Switch, _te)
+ throw ::std::runtime_error("TODO: Terminator::Switch");
+ TU_ARM(bb.terminator, SwitchValue, _te)
+ throw ::std::runtime_error("TODO: Terminator::SwitchValue");
+ TU_ARM(bb.terminator, Call, te) {
+ if( te.fcn.is_Intrinsic() ) {
+ throw ::std::runtime_error("TODO: Terminator::Call - intrinsic");
+ }
+ else {
+ const ::HIR::Path* fcn_p;
+ if( te.fcn.is_Path() ) {
+ fcn_p = &te.fcn.as_Path();
+ }
+ else {
+ ::HIR::TypeRef ty;
+ auto v = state.read_lvalue_with_ty(te.fcn.as_Value(), ty);
+ // TODO: Assert type
+ // TODO: Assert offset/content.
+ assert(v.as_usize() == 0);
+ fcn_p = &v.allocation.alloc().relocations.at(0).backing_alloc.fcn();
+ }
+
+ ::std::vector<Value> sub_args; sub_args.reserve(te.args.size());
+ for(const auto& a : te.args)
+ {
+ sub_args.push_back( state.param_to_value(a) );
+ }
+ ::std::cout << "TODO: Call " << *fcn_p << ::std::endl;
+ MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args));
+ }
+ throw ::std::runtime_error("TODO: Terminator::Call");
+ } break;
}
throw "";
}
diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp
index f056481b..90d599c8 100644
--- a/tools/standalone_miri/module_tree.cpp
+++ b/tools/standalone_miri/module_tree.cpp
@@ -3,6 +3,7 @@
//
#include "module_tree.hpp"
#include "lex.hpp"
+#include "value.hpp"
#include <iostream>
ModuleTree::ModuleTree()
@@ -73,7 +74,7 @@ bool Parser::parse_one()
else if( lex.consume_if("fn") )
{
auto p = parse_path();
- //::std::cout << "DEBUG:p arse_one - fn " << p << ::std::endl;
+ //::std::cout << "DEBUG: parse_one - fn " << p << ::std::endl;
lex.check_consume('(');
::std::vector<::HIR::TypeRef> arg_tys;
@@ -91,17 +92,33 @@ bool Parser::parse_one()
}
auto body = parse_body();
- tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(arg_tys), rv_ty, ::std::move(body) }) );
+ auto p2 = p;
+ tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, ::std::move(body) }) );
}
else if( lex.consume_if("static") )
{
auto p = parse_path();
//::std::cout << "DEBUG: parse_one - static " << p << ::std::endl;
+ lex.check_consume(':');
+ auto ty = parse_type();
+ // TODO: externs?
lex.check_consume('=');
- // TODO: Body? Value?
- //auto body = parse_body();
- //auto data = ::std::move(lex.consume().strval);
- throw "TODO";
+ lex.check(TokenClass::String);
+ auto data = ::std::move(lex.consume().strval);
+ if( lex.consume_if('{') )
+ {
+ while( !lex.consume_if('}') )
+ {
+ // TODO: Parse relocation entries
+ throw "TODO";
+ }
+ }
+ lex.check_consume(';');
+
+ Value val = Value(ty);
+ val.write_bytes(0, data.data(), data.size());
+
+ tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(val) ));
}
else if( lex.consume_if("type") )
{
@@ -354,7 +371,7 @@ bool Parser::parse_one()
else if( p.lex.consume_if("false") ) {
return ::MIR::Constant::make_Bool({ false });
}
- else if( p.lex.consume_if("&") ) {
+ else if( p.lex.consume_if("ADDROF") ) {
auto path = p.parse_path();
return ::MIR::Constant::make_ItemAddr({ ::std::move(path) });
@@ -371,6 +388,7 @@ bool Parser::parse_one()
if( p.lex.next() == TokenClass::Integer || p.lex.next() == TokenClass::String || p.lex.next() == TokenClass::ByteString
|| p.lex.next() == '+' || p.lex.next() == '-' || p.lex.next() == '&'
|| p.lex.next() == "true" || p.lex.next() == "false"
+ || p.lex.next() == "ADDROF"
)
{
return parse_const(p);
@@ -432,6 +450,7 @@ bool Parser::parse_one()
if( lex.next() == TokenClass::Integer || lex.next() == TokenClass::String || lex.next() == TokenClass::ByteString
|| lex.next() == '+' || lex.next() == '-'
|| lex.next() == "true" || lex.next() == "false"
+ || lex.next() == "ADDROF"
)
{
src_rval = H::parse_const(*this);
@@ -1203,4 +1222,32 @@ const Function& ModuleTree::get_function(const ::HIR::Path& p) const
throw "";
}
return it->second;
+}
+const Function* ModuleTree::get_function_opt(const ::HIR::Path& p) const
+{
+ auto it = functions.find(p);
+ if(it == functions.end())
+ {
+ return nullptr;
+ }
+ return &it->second;
+}
+Value& ModuleTree::get_static(const ::HIR::Path& p)
+{
+ auto it = statics.find(p);
+ if(it == statics.end())
+ {
+ ::std::cerr << "Unable to find static " << p << " for invoke" << ::std::endl;
+ throw "";
+ }
+ return it->second;
+}
+Value* ModuleTree::get_static_opt(const ::HIR::Path& p)
+{
+ auto it = statics.find(p);
+ if(it == statics.end())
+ {
+ return nullptr;
+ }
+ return &it->second;
} \ No newline at end of file
diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp
index ce831621..96a77718 100644
--- a/tools/standalone_miri/module_tree.hpp
+++ b/tools/standalone_miri/module_tree.hpp
@@ -10,8 +10,11 @@
#include "../../src/mir/mir.hpp"
#include "hir_sim.hpp"
+struct Value;
+
struct Function
{
+ ::HIR::Path my_path;
::std::vector<::HIR::TypeRef> args;
::HIR::TypeRef ret_ty;
::MIR::Function m_mir;
@@ -25,6 +28,9 @@ class ModuleTree
::std::set<::std::string> loaded_files;
::std::map<::HIR::Path, Function> functions;
+ ::std::map<::HIR::Path, Value> statics;
+ // TODO: statics
+
// Hack: Tuples are stored as `::""::<A,B,C,...>`
::std::map<::HIR::GenericPath, ::std::unique_ptr<DataType>> data_types;
public:
@@ -34,6 +40,9 @@ public:
::HIR::SimplePath find_lang_item(const char* name) const;
const Function& get_function(const ::HIR::Path& p) const;
+ const Function* get_function_opt(const ::HIR::Path& p) const;
+ Value& get_static(const ::HIR::Path& p);
+ Value* get_static_opt(const ::HIR::Path& p);
};
// struct/union/enum
diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp
index e04154f6..59b68ea0 100644
--- a/tools/standalone_miri/value.cpp
+++ b/tools/standalone_miri/value.cpp
@@ -8,6 +8,54 @@
#include <iomanip>
#include <algorithm>
+
+AllocationPtr Allocation::new_alloc(size_t size)
+{
+ Allocation* rv = new Allocation();
+ rv->refcount = 1;
+ rv->data.resize( (size + 8-1) / 8 ); // QWORDS
+ rv->mask.resize( (size + 8-1) / 8 ); // bitmap bytes
+ return AllocationPtr(rv);
+}
+AllocationPtr AllocationPtr::new_fcn(::HIR::Path p)
+{
+ AllocationPtr rv;
+ auto* ptr = new ::HIR::Path(::std::move(p));
+ rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::Function) );
+ return rv;
+}
+AllocationPtr::AllocationPtr(const AllocationPtr& x):
+ m_ptr(x.m_ptr)
+{
+ if( is_alloc() ) {
+ assert(alloc().refcount != SIZE_MAX);
+ alloc().refcount += 1;
+ }
+}
+AllocationPtr::~AllocationPtr()
+{
+ if( *this )
+ {
+ switch(get_ty())
+ {
+ case Ty::Allocation: {
+ auto* ptr = &alloc();
+ ptr->refcount -= 1;
+ if(ptr->refcount == 0)
+ delete ptr;
+ } break;
+ case Ty::Function: {
+ auto* ptr = const_cast<::HIR::Path*>(&fcn());
+ delete ptr;
+ } break;
+ case Ty::Unused1: {
+ } break;
+ case Ty::Unused2: {
+ } break;
+ }
+ }
+}
+
Value::Value()
{
this->meta.direct_data.size = 0;
@@ -18,6 +66,7 @@ Value::Value(::HIR::TypeRef ty)
{
size_t size = ty.get_size();
#if 1
+ // Support inline data if the data will fit within the inline region (which is the size of the metadata)
if( ty.get_size() <= sizeof(this->meta.direct_data.data) )
{
struct H
@@ -26,6 +75,11 @@ Value::Value(::HIR::TypeRef ty)
{
if( ty.wrappers.empty() || ::std::all_of(ty.wrappers.begin(), ty.wrappers.end(), [](const auto& x){ return x.type == TypeWrapper::Ty::Array; }) )
{
+ // TODO: Function pointers should be _pointers_
+ if( ty.inner_type == RawType::Function )
+ {
+ return true;
+ }
// Check the inner type
if( ty.inner_type != RawType::Composite )
{
@@ -45,28 +99,69 @@ Value::Value(::HIR::TypeRef ty)
if( ! H::has_pointer(ty) )
{
// Will fit in a inline allocation, nice.
+ ::std::cout << "Value::Value(): No pointers in " << ty << ", storing inline" << ::std::endl;
this->meta.direct_data.size = static_cast<uint8_t>(size);
+ this->meta.direct_data.mask[0] = 0;
+ this->meta.direct_data.mask[1] = 0;
return ;
}
}
#endif
// Fallback: Make a new allocation
- throw "TODO";
+ ::std::cout << "Value::Value(): Creating allocation for " << ty << ::std::endl;
+ this->allocation = Allocation::new_alloc(size);
+ this->meta.indirect_meta.offset = 0;
+ this->meta.indirect_meta.size = size;
+}
+Value Value::new_fnptr(const ::HIR::Path& fn_path)
+{
+ Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::Function }) );
+ assert(rv.allocation);
+ rv.allocation.alloc().relocations.push_back(Relocation { 0, AllocationPtr::new_fcn(fn_path) });
+ rv.allocation.alloc().data.at(0) = 0;
+ rv.allocation.alloc().mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes
+ return rv;
}
void Value::check_bytes_valid(size_t ofs, size_t size) const
{
if( this->allocation )
{
- throw "TODO";
+ const auto& alloc = this->allocation.alloc();
+ if( ofs >= this->meta.indirect_meta.size || ofs+size > this->meta.indirect_meta.size ) {
+ ::std::cerr << "ERROR: OOB read" << ::std::endl;
+ throw "ERROR";
+ }
+ ofs += this->meta.indirect_meta.offset;
+ //assert(ofs + size < alloc.size());
+ for(size_t i = ofs; i < ofs + size; i++)
+ {
+ if( !(alloc.mask[i/8] & (1 << i%8)) )
+ {
+ ::std::cerr << "ERROR: Invalid bytes in value" << ::std::endl;
+ throw "ERROR";
+ }
+ }
}
else
{
- for(size_t i = 0; i < this->meta.direct_data.size; i++)
+ if( size == 0 && this->meta.direct_data.size > 0 ) {
+ return ;
+ }
+ if( ofs >= this->meta.direct_data.size ) {
+ ::std::cerr << "ERROR: OOB read" << ::std::endl;
+ throw "ERROR";
+ }
+ if( ofs+size > this->meta.direct_data.size ) {
+ ::std::cerr << "ERROR: OOB read" << ::std::endl;
+ throw "ERROR";
+ }
+ for(size_t i = ofs; i < ofs + size; i++)
{
if( !(this->meta.direct_data.mask[i/8] & (1 << i%8)) )
{
+ ::std::cerr << "ERROR: Invalid bytes in value" << ::std::endl;
throw "ERROR";
}
}
@@ -76,7 +171,14 @@ void Value::mark_bytes_valid(size_t ofs, size_t size)
{
if( this->allocation )
{
- throw "TODO";
+ auto& alloc = this->allocation.alloc();
+ // TODO: Assert range.
+ ofs += this->meta.indirect_meta.offset;
+ assert( (ofs+size+8-1) / 8 < alloc.mask.size() );
+ for(size_t i = ofs; i < ofs + size; i++)
+ {
+ alloc.mask[i/8] |= (1 << i%8);
+ }
}
else
{
@@ -93,7 +195,29 @@ Value Value::read_value(size_t ofs, size_t size) const
check_bytes_valid(ofs, size);
if( this->allocation )
{
- throw "TODO";
+ const auto& alloc = this->allocation.alloc();
+ // TODO: Determine if this can become an inline allocation.
+ bool has_reloc = false;
+ for(const auto& r : alloc.relocations)
+ {
+ if( this->meta.indirect_meta.offset+ofs <= r.slot_ofs && r.slot_ofs < this->meta.indirect_meta.offset + ofs + size )
+ {
+ has_reloc = true;
+ }
+ }
+ Value rv;
+ if( has_reloc && size < sizeof(this->meta.direct_data.data) )
+ {
+ rv.allocation = Allocation::new_alloc(size);
+ rv.meta.indirect_meta.offset = 0;
+ rv.meta.indirect_meta.size = size;
+ }
+ else
+ {
+ rv.meta.direct_data.size = static_cast<uint8_t>(size);
+ }
+ rv.write_bytes(0, this->data_ptr() + ofs, size);
+ return rv;
}
else
{
@@ -114,7 +238,12 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count)
{
if( this->allocation )
{
- throw "TODO";
+ if(ofs >= this->meta.indirect_meta.size )
+ throw "ERROR";
+ if(count > this->meta.indirect_meta.size )
+ throw "ERROR";
+ if(ofs+count > this->meta.indirect_meta.size )
+ throw "ERROR";
}
else
{
@@ -124,21 +253,36 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count)
throw "ERROR";
if(ofs+count > this->meta.direct_data.size )
throw "ERROR";
- ::std::memcpy(this->meta.direct_data.data+ofs, src, count);
- mark_bytes_valid(ofs, count);
}
+ ::std::memcpy(this->data_ptr() + ofs, src, count);
+ mark_bytes_valid(ofs, count);
}
void Value::write_value(size_t ofs, Value v)
{
if( v.allocation )
{
- throw "TODO";
+ v.check_bytes_valid(0, v.meta.indirect_meta.size);
+ const auto& src_alloc = v.allocation.alloc();
+ write_bytes(ofs, v.data_ptr(), v.meta.indirect_meta.size);
+ // Find any relocations that apply and copy those in.
+ // - Any relocations in the source within `v.meta.indirect_meta.offset` .. `v.meta.indirect_meta.offset + v.meta.indirect_meta.size`
+ for(const auto& r : src_alloc.relocations)
+ {
+ // TODO: Negative offsets in destination?
+ if( v.meta.indirect_meta.offset <= r.slot_ofs && r.slot_ofs < v.meta.indirect_meta.offset + v.meta.indirect_meta.size )
+ {
+ // Applicable
+ if( !this->allocation ) {
+ throw ::std::runtime_error("TODO: Writing value with a relocation into a slot without a relocation");
+ }
+ this->allocation.alloc().relocations.push_back( r );
+ }
+ }
}
else
{
v.check_bytes_valid(0, v.meta.direct_data.size);
write_bytes(ofs, v.meta.direct_data.data, v.meta.direct_data.size);
- mark_bytes_valid(ofs, meta.direct_data.size);
}
}
@@ -146,7 +290,7 @@ size_t Value::as_usize() const
{
uint64_t v;
this->read_bytes(0, &v, 8);
- // TODO: Handle endian
+ // TODO: Handle endian and different architectures
return v;
}
::std::ostream& operator<<(::std::ostream& os, const Value& v)
@@ -155,7 +299,22 @@ size_t Value::as_usize() const
os << ::std::hex;
if( v.allocation )
{
- throw "TODO";
+ const auto& alloc = v.allocation.alloc();
+ for(size_t i = 0; i < v.meta.indirect_meta.size; i++)
+ {
+ if( i != 0 )
+ os << " ";
+ size_t j = i + v.meta.indirect_meta.offset;
+
+ if( alloc.mask[j/8] & (1 << i%8) )
+ {
+ os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[j];
+ }
+ else
+ {
+ os << "--";
+ }
+ }
}
else
{
diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp
index 65403a81..9f9e68f4 100644
--- a/tools/standalone_miri/value.hpp
+++ b/tools/standalone_miri/value.hpp
@@ -6,33 +6,95 @@
#include <vector>
#include <memory>
#include <cstdint>
+#include <cassert>
namespace HIR {
struct TypeRef;
+ struct Path;
}
class Allocation;
+
class AllocationPtr
{
friend class Allocation;
- Allocation* m_ptr;
+ void* m_ptr;
+public:
+
+ enum class Ty
+ {
+ Allocation,
+ Function, // m_ptr is a pointer to the function.
+ Unused1,
+ Unused2,
+ };
+
+private:
+ AllocationPtr(Allocation* p):
+ m_ptr(p)
+ {
+ }
public:
AllocationPtr(): m_ptr(nullptr) {}
+ AllocationPtr(AllocationPtr&& x): m_ptr(x.m_ptr) {
+ x.m_ptr = nullptr;
+ }
+ AllocationPtr(const AllocationPtr& x);
+ ~AllocationPtr();
+ static AllocationPtr new_fcn(::HIR::Path p);
+
+ AllocationPtr& operator=(AllocationPtr&& x) {
+ this->~AllocationPtr();
+ this->m_ptr = x.m_ptr;
+ x.m_ptr = nullptr;
+ return *this;
+ }
operator bool() const { return m_ptr != 0; }
- Allocation& operator*() { return *m_ptr; }
- Allocation* operator->() { return m_ptr; }
+ bool is_alloc() {
+ return *this && get_ty() == Ty::Allocation;
+ }
+ Allocation& alloc() {
+ assert(get_ty() == Ty::Allocation);
+ return *static_cast<Allocation*>(get_ptr());
+ }
+ const Allocation& alloc() const {
+ assert(get_ty() == Ty::Allocation);
+ return *static_cast<Allocation*>(get_ptr());
+ }
+ const ::HIR::Path& fcn() const {
+ assert(get_ty() == Ty::Function);
+ return *static_cast<const ::HIR::Path*>(get_ptr());
+ }
+
+ Ty get_ty() const {
+ return static_cast<Ty>( reinterpret_cast<uintptr_t>(m_ptr) & 3 );
+ }
+private:
+ void* get_ptr() const {
+ return reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(m_ptr) & ~3 );
+ }
};
struct Relocation
{
+ // Offset within parent allocation where this relocation is performed.
+ // TODO: Size?
size_t slot_ofs;
AllocationPtr backing_alloc;
};
class Allocation
{
+ friend class AllocationPtr;
size_t refcount;
+ // TODO: Read-only flag?
public:
+ static AllocationPtr new_alloc(size_t size);
+
+ const uint8_t* data_ptr() const { return reinterpret_cast<const uint8_t*>(this->data.data()); }
+ uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->data.data()); }
+
::std::vector<uint64_t> data;
+ ::std::vector<uint8_t> mask;
::std::vector<Relocation> relocations;
};
@@ -54,6 +116,7 @@ struct Value
Value();
Value(::HIR::TypeRef ty);
+ static Value new_fnptr(const ::HIR::Path& fn_path);
void check_bytes_valid(size_t ofs, size_t size) const;
void mark_bytes_valid(size_t ofs, size_t size);
@@ -65,5 +128,8 @@ struct Value
void write_bytes(size_t ofs, const void* src, size_t count);
size_t as_usize() const;
+private:
+ const uint8_t* data_ptr() const { return allocation ? allocation.alloc().data_ptr() + meta.indirect_meta.offset : meta.direct_data.data; }
+ uint8_t* data_ptr() { return allocation ? allocation.alloc().data_ptr() + meta.indirect_meta.offset : meta.direct_data.data; }
};
extern ::std::ostream& operator<<(::std::ostream& os, const Value& v);