From 225353d8bbad5730c941fc88e854627004e74f2c Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Tue, 9 Sep 2014 23:12:09 -0700 Subject: [PATCH] Add a Rust string ostream for LLVM --- src/librustc/middle/trans/type_.rs | 21 +++++++-------------- src/librustc_llvm/lib.rs | 30 ++++++++++++++++++++++++++++-- src/rustllvm/RustWrapper.cpp | 12 ++++-------- src/rustllvm/rustllvm.h | 28 ++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 24 deletions(-) diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index 3df1ce32fc7..a6a30d6ba85 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -21,11 +21,10 @@ use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel}; use std::c_str::ToCStr; use std::mem; -use std::string; use std::cell::RefCell; use std::collections::HashMap; -use libc::{c_uint, c_void, free}; +use libc::c_uint; #[deriving(Clone, PartialEq, Show)] pub struct Type { @@ -339,12 +338,9 @@ impl TypeNames { } pub fn type_to_string(&self, ty: Type) -> String { - unsafe { - let s = llvm::LLVMTypeToString(ty.to_ref()); - let ret = string::raw::from_buf(s as *const u8); - free(s as *mut c_void); - ret - } + llvm::build_string(|s| unsafe { + llvm::LLVMWriteTypeToString(ty.to_ref(), s); + }).expect("non-UTF8 type description from LLVM") } pub fn types_to_str(&self, tys: &[Type]) -> String { @@ -353,11 +349,8 @@ impl TypeNames { } pub fn val_to_string(&self, val: ValueRef) -> String { - unsafe { - let s = llvm::LLVMValueToString(val); - let ret = string::raw::from_buf(s as *const u8); - free(s as *mut c_void); - ret - } + llvm::build_string(|s| unsafe { + llvm::LLVMWriteValueToString(val, s); + }).expect("nun-UTF8 value description from LLVM") } } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index ceb29ddcf8f..354448085b9 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -28,6 +28,8 @@ extern crate libc; use std::c_str::ToCStr; +use std::cell::RefCell; +use std::{raw, mem}; use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char}; use libc::{c_longlong, c_ulonglong}; use debuginfo::{DIBuilderRef, DIDescriptor, @@ -1839,8 +1841,8 @@ extern { -> ValueRef; pub fn LLVMDICompositeTypeSetTypeArray(CompositeType: ValueRef, TypeArray: ValueRef); - pub fn LLVMTypeToString(Type: TypeRef) -> *const c_char; - pub fn LLVMValueToString(value_ref: ValueRef) -> *const c_char; + pub fn LLVMWriteTypeToString(Type: TypeRef, s: RustStringRef); + pub fn LLVMWriteValueToString(value_ref: ValueRef, s: RustStringRef); pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef; @@ -2046,6 +2048,30 @@ pub fn get_param(llfn: ValueRef, index: c_uint) -> ValueRef { } } +pub enum RustString_opaque {} +pub type RustStringRef = *mut RustString_opaque; +type RustStringRepr = *mut RefCell>; + +/// Appending to a Rust string -- used by raw_rust_string_ostream. +#[no_mangle] +pub unsafe extern "C" fn rust_llvm_string_write_impl(sr: RustStringRef, + ptr: *const c_char, + size: size_t) { + let slice: &[u8] = mem::transmute(raw::Slice { + data: ptr as *const u8, + len: size as uint, + }); + + let sr: RustStringRepr = mem::transmute(sr); + (*sr).borrow_mut().push_all(slice); +} + +pub fn build_string(f: |RustStringRef|) -> Option { + let mut buf = RefCell::new(Vec::new()); + f(&mut buf as RustStringRepr as RustStringRef); + String::from_utf8(buf.unwrap()).ok() +} + // FIXME #15460 - create a public function that actually calls our // static LLVM symbols. Otherwise the linker will just throw llvm // away. We're just calling lots of stuff until we transitively get diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index cdd36d7f458..5893b582cd8 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -645,22 +645,18 @@ extern "C" void LLVMDICompositeTypeSetTypeArray( #endif } -extern "C" char *LLVMTypeToString(LLVMTypeRef Type) { - std::string s; - llvm::raw_string_ostream os(s); +extern "C" void LLVMWriteTypeToString(LLVMTypeRef Type, RustStringRef str) { + raw_rust_string_ostream os(str); unwrap(Type)->print(os); - return strdup(os.str().data()); } -extern "C" char *LLVMValueToString(LLVMValueRef Value) { - std::string s; - llvm::raw_string_ostream os(s); +extern "C" void LLVMWriteValueToString(LLVMValueRef Value, RustStringRef str) { + raw_rust_string_ostream os(str); os << "("; unwrap(Value)->getType()->print(os); os << ":"; unwrap(Value)->print(os); os << ")"; - return strdup(os.str().data()); } #if LLVM_VERSION_MINOR >= 5 diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index 5722eea48d7..92f94b0e8e5 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -69,3 +69,31 @@ #endif void LLVMRustSetLastError(const char*); + +typedef struct OpaqueRustString *RustStringRef; + +extern "C" void +rust_llvm_string_write_impl(RustStringRef str, const char *ptr, size_t size); + +class raw_rust_string_ostream : public llvm::raw_ostream { + RustStringRef str; + uint64_t pos; + + void write_impl(const char *ptr, size_t size) override { + rust_llvm_string_write_impl(str, ptr, size); + pos += size; + } + + uint64_t current_pos() const override { + return pos; + } + +public: + explicit raw_rust_string_ostream(RustStringRef str) + : str(str), pos(0) { } + + ~raw_rust_string_ostream() { + // LLVM requires this. + flush(); + } +};