diff options
-rw-r--r-- | tools/standalone_miri/miri.cpp | 173 | ||||
-rw-r--r-- | tools/standalone_miri/miri.hpp | 2 |
2 files changed, 148 insertions, 27 deletions
diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index ef8a71c9..d4bb267c 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -269,15 +269,15 @@ struct MirHelpers case ::MIR::LValue::Storage::TAGDEAD: throw ""; // --> Slots TU_ARM(lv_root, Return, _e) { - ty = this->frame.fcn.ret_ty; + ty = this->frame.fcn->ret_ty; return ValueRef(this->frame.ret); } break; TU_ARM(lv_root, Local, e) { - ty = this->frame.fcn.m_mir.locals.at(e); + ty = this->frame.fcn->m_mir.locals.at(e); return ValueRef(this->frame.locals.at(e)); } break; TU_ARM(lv_root, Argument, e) { - ty = this->frame.fcn.args.at(e); + ty = this->frame.fcn->args.at(e); return ValueRef(this->frame.args.at(e)); } break; TU_ARM(lv_root, Static, e) { @@ -571,8 +571,8 @@ InterpreterThread::~InterpreterThread() } else { - ::std::cout << frame.fcn.my_path << " BB" << frame.bb_idx << "/"; - if( frame.stmt_idx == frame.fcn.m_mir.blocks.at(frame.bb_idx).statements.size() ) + ::std::cout << frame.fcn->my_path << " BB" << frame.bb_idx << "/"; + if( frame.stmt_idx == frame.fcn->m_mir.blocks.at(frame.bb_idx).statements.size() ) ::std::cout << "TERM"; else ::std::cout << frame.stmt_idx; @@ -594,8 +594,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) assert( !this->m_stack.empty() ); assert( !this->m_stack.back().cb ); auto& cur_frame = this->m_stack.back(); - TRACE_FUNCTION_R(cur_frame.fcn.my_path << " BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx, ""); - const auto& bb = cur_frame.fcn.m_mir.blocks.at( cur_frame.bb_idx ); + TRACE_FUNCTION_R(cur_frame.fcn->my_path << " BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx, ""); + const auto& bb = cur_frame.fcn->m_mir.blocks.at( cur_frame.bb_idx ); const size_t MAX_STACK_DEPTH = 40; if( this->m_stack.size() > MAX_STACK_DEPTH ) @@ -795,7 +795,15 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::Bool: LOG_TODO("Cast to " << re.type); case RawType::Char: - LOG_TODO("Cast to " << re.type); + switch(src_ty.inner_type) + { + case RawType::Char: new_val.write_u32(0, src_value.read_u32(0) ); break; + case RawType::U8: new_val.write_u32(0, src_value.read_u8(0) ); break; + default: + LOG_ERROR("Cat from " << src_ty << " to char isn't valid"); + break; + } + break; case RawType::USize: case RawType::U8: case RawType::U16: @@ -1031,6 +1039,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::I8 : res = res != 0 ? res : Ops::do_compare(v_l.read_i8 (0), v_r.read_i8 (0)); break; case RawType::USize: res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0)); break; case RawType::ISize: res = res != 0 ? res : Ops::do_compare(v_l.read_isize(0), v_r.read_isize(0)); break; + case RawType::Char: res = res != 0 ? res : Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0)); break; default: LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l); } @@ -1440,8 +1449,65 @@ bool InterpreterThread::step_one(Value& out_thread_result) } cur_frame.bb_idx = te.targets.at(found_target); } break; - TU_ARM(bb.terminator, SwitchValue, _te) - LOG_TODO("Terminator::SwitchValue"); + TU_ARM(bb.terminator, SwitchValue, te) { + ::HIR::TypeRef ty; + auto v = state.get_value_and_type(te.val, ty); + TU_MATCH_HDRA( (te.values), {) + TU_ARMA(Unsigned, vals) { + LOG_ASSERT(vals.size() == te.targets.size(), "Mismatch in SwitchValue target/value list lengths"); + // Read an unsigned value + if( ty.get_wrapper() ) { + LOG_ERROR("Terminator::SwitchValue::Unsigned with wrapped type - " << ty); + } + uint64_t switch_val; + switch(ty.inner_type) + { + case RawType::U8: switch_val = v.read_u8(0); break; + case RawType::U16: switch_val = v.read_u16(0); break; + case RawType::U32: switch_val = v.read_u32(0); break; + case RawType::U64: switch_val = v.read_u64(0); break; + case RawType::U128: LOG_TODO("Terminator::SwitchValue::Unsigned with u128"); + case RawType::USize: switch_val = v.read_usize(0); break; + default: + LOG_ERROR("Terminator::SwitchValue::Unsigned with unexpected type - " << ty); + } + + auto it = ::std::find(vals.begin(), vals.end(), switch_val); + if( it != vals.end() ) + { + auto idx = it - vals.begin(); + LOG_TRACE("- " << switch_val << " matched arm " << idx); + cur_frame.bb_idx = te.targets.at(idx); + } + else + { + LOG_TRACE("- " << switch_val << " not matched, taking default arm"); + cur_frame.bb_idx = te.def_target; + } + } + TU_ARMA(Signed, vals) { + if( ty.get_wrapper() ) { + LOG_ERROR("Terminator::SwitchValue::Signed with wrapped type - " << ty); + } + int64_t switch_val; + switch(ty.inner_type) + { + case RawType::I8: switch_val = v.read_i8(0); break; + case RawType::I16: switch_val = v.read_i16(0); break; + case RawType::I32: switch_val = v.read_i32(0); break; + case RawType::I64: switch_val = v.read_i64(0); break; + case RawType::I128: LOG_TODO("Terminator::SwitchValue::Signed with i128"); + case RawType::ISize: switch_val = v.read_isize(0); break; + default: + LOG_ERROR("Terminator::SwitchValue::Signed with unexpected type - " << ty); + } + LOG_TODO("Terminator::SwitchValue (signed) - " << ty << " " << switch_val); + } + TU_ARMA(String, vals) { + LOG_TODO("Terminator::SwitchValue (string) - " << ty << " " << v); + } + } + } TU_ARM(bb.terminator, Call, te) { ::std::vector<Value> sub_args; sub_args.reserve(te.args.size()); for(const auto& a : te.args) @@ -1488,7 +1554,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) return false; } } - LOG_DEBUG(te.ret_val << " = " << rv << " (resume " << cur_frame.fcn.my_path << ")"); + LOG_DEBUG(te.ret_val << " = " << rv << " (resume " << cur_frame.fcn->my_path << ")"); state.write_lvalue(te.ret_val, rv); cur_frame.bb_idx = te.ret_block; } break; @@ -1528,19 +1594,19 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) auto& cur_frame = this->m_stack.back(); MirHelpers state { *this, cur_frame }; - const auto& blk = cur_frame.fcn.m_mir.blocks.at( cur_frame.bb_idx ); + const auto& blk = cur_frame.fcn->m_mir.blocks.at( cur_frame.bb_idx ); if( cur_frame.stmt_idx < blk.statements.size() ) { assert( blk.statements[cur_frame.stmt_idx].is_Drop() ); cur_frame.stmt_idx ++; - LOG_DEBUG("DROP complete (resume " << cur_frame.fcn.my_path << ")"); + LOG_DEBUG("DROP complete (resume " << cur_frame.fcn->my_path << ")"); } else { assert( blk.terminator.is_Call() ); const auto& te = blk.terminator.as_Call(); - LOG_DEBUG(te.ret_val << " = " << res_v << " (resume " << cur_frame.fcn.my_path << ")"); + LOG_DEBUG(te.ret_val << " = " << res_v << " (resume " << cur_frame.fcn->my_path << ")"); state.write_lvalue(te.ret_val, res_v); cur_frame.stmt_idx = 0; @@ -1552,7 +1618,7 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) } InterpreterThread::StackFrame::StackFrame(const Function& fcn, ::std::vector<Value> args): - fcn(fcn), + fcn(&fcn), ret( fcn.ret_ty == RawType::Unreachable ? Value() : Value(fcn.ret_ty) ), args( ::std::move(args) ), locals( ), @@ -1633,6 +1699,27 @@ extern "C" { #endif bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, const ::std::string& abi, ::std::vector<Value> args) { + struct FfiHelpers { + static const char* read_cstr(const Value& v, size_t ptr_ofs, size_t* out_strlen=nullptr) + { + bool _is_mut; + size_t size; + // Get the base pointer and allocation size (checking for at least one valid byte to start with) + const char* ptr = reinterpret_cast<const char*>( v.read_pointer_unsafe(0, 1, /*out->*/ size, _is_mut) ); + size_t len = 0; + // Seek until either out of space, or a NUL is found + while(size -- && *ptr) + { + ptr ++; + len ++; + } + if( out_strlen ) + { + *out_strlen = len; + } + return reinterpret_cast<const char*>(v.read_pointer_const(0, len + 1)); // Final read will trigger an error if the NUL isn't there + } + }; if( link_name == "__rust_allocate" || link_name == "__rust_alloc" ) { static unsigned s_alloc_count = 0; @@ -1923,21 +2010,35 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c else if( link_name == "strlen" ) { // strlen - custom implementation to ensure validity - bool _is_mut; - size_t size; - const char* ptr = reinterpret_cast<const char*>( args.at(0).read_pointer_unsafe(0, 1, size, _is_mut) ); size_t len = 0; - while(size -- && *ptr) - { - ptr ++; - len ++; - } - args.at(0).read_pointer_const(0, len + 1); + FfiHelpers::read_cstr(args.at(0), 0, &len); //rv = Value::new_usize(len); rv = Value(::HIR::TypeRef(RawType::USize)); rv.write_usize(0, len); } + else if( link_name == "getenv" ) + { + const auto* name = FfiHelpers::read_cstr(args.at(0), 0); + LOG_DEBUG("getenv(\"" << name << "\")"); + const auto* ret_ptr = getenv(name); + if( ret_ptr ) + { + LOG_DEBUG("= \"" << ret_ptr << "\""); + rv = Value::new_ffiptr(FFIPointer::new_const_bytes(ret_ptr, strlen(ret_ptr)+1)); + } + else + { + LOG_DEBUG("= NULL"); + rv = Value(::HIR::TypeRef(RawType::USize)); + rv.create_allocation(); + rv.write_usize(0,0); + } + } + else if( link_name == "setenv" ) + { + LOG_TODO("Allow `setenv` without incurring thread unsafety"); + } // Allocators! else { @@ -2367,8 +2468,28 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ for(uint64_t i = 0; i < count; i ++) { auto ptr = Value::new_pointer(pty, ofs, ptr_reloc); - if( !drop_value(ptr, ity) ) { - LOG_TODO("Handle closure looping when dropping a slice"); + if( !drop_value(ptr, ity) ) + { + // - This is trying to invoke custom drop glue, need to suspend this operation and come back later + + // > insert a new frame shim BEFORE the current top (which would be the frame created by + // `drop_value` calling a function) + m_stack.insert( m_stack.end() - 1, StackFrame::make_wrapper([this,pty,ity,ptr_reloc,count, i,ofs](Value& rv, Value drop_rv) mutable { + assert(i < count); + i ++; + if( i < count ) + { + auto ptr = Value::new_pointer(pty, ofs, ptr_reloc); + ofs += ity.get_size(); + assert(!drop_value(ptr, ity)); + return false; + } + else + { + return true; + } + }) ); + return false; } ofs += ity.get_size(); } diff --git a/tools/standalone_miri/miri.hpp b/tools/standalone_miri/miri.hpp index 2966e7bf..3181a116 100644 --- a/tools/standalone_miri/miri.hpp +++ b/tools/standalone_miri/miri.hpp @@ -36,7 +36,7 @@ class InterpreterThread struct StackFrame { ::std::function<bool(Value&,Value)> cb; - const Function& fcn; + const Function* fcn; Value ret; ::std::vector<Value> args; ::std::vector<Value> locals; |