Skip to content

Commit 225353d

Browse files
author
Keegan McAllister
committed
Add a Rust string ostream for LLVM
1 parent 77b3a7b commit 225353d

File tree

4 files changed

+67
-24
lines changed

4 files changed

+67
-24
lines changed

src/librustc/middle/trans/type_.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,10 @@ use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel};
2121

2222
use std::c_str::ToCStr;
2323
use std::mem;
24-
use std::string;
2524
use std::cell::RefCell;
2625
use std::collections::HashMap;
2726

28-
use libc::{c_uint, c_void, free};
27+
use libc::c_uint;
2928

3029
#[deriving(Clone, PartialEq, Show)]
3130
pub struct Type {
@@ -339,12 +338,9 @@ impl TypeNames {
339338
}
340339

341340
pub fn type_to_string(&self, ty: Type) -> String {
342-
unsafe {
343-
let s = llvm::LLVMTypeToString(ty.to_ref());
344-
let ret = string::raw::from_buf(s as *const u8);
345-
free(s as *mut c_void);
346-
ret
347-
}
341+
llvm::build_string(|s| unsafe {
342+
llvm::LLVMWriteTypeToString(ty.to_ref(), s);
343+
}).expect("non-UTF8 type description from LLVM")
348344
}
349345

350346
pub fn types_to_str(&self, tys: &[Type]) -> String {
@@ -353,11 +349,8 @@ impl TypeNames {
353349
}
354350

355351
pub fn val_to_string(&self, val: ValueRef) -> String {
356-
unsafe {
357-
let s = llvm::LLVMValueToString(val);
358-
let ret = string::raw::from_buf(s as *const u8);
359-
free(s as *mut c_void);
360-
ret
361-
}
352+
llvm::build_string(|s| unsafe {
353+
llvm::LLVMWriteValueToString(val, s);
354+
}).expect("nun-UTF8 value description from LLVM")
362355
}
363356
}

src/librustc_llvm/lib.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
extern crate libc;
2929

3030
use std::c_str::ToCStr;
31+
use std::cell::RefCell;
32+
use std::{raw, mem};
3133
use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char};
3234
use libc::{c_longlong, c_ulonglong};
3335
use debuginfo::{DIBuilderRef, DIDescriptor,
@@ -1839,8 +1841,8 @@ extern {
18391841
-> ValueRef;
18401842

18411843
pub fn LLVMDICompositeTypeSetTypeArray(CompositeType: ValueRef, TypeArray: ValueRef);
1842-
pub fn LLVMTypeToString(Type: TypeRef) -> *const c_char;
1843-
pub fn LLVMValueToString(value_ref: ValueRef) -> *const c_char;
1844+
pub fn LLVMWriteTypeToString(Type: TypeRef, s: RustStringRef);
1845+
pub fn LLVMWriteValueToString(value_ref: ValueRef, s: RustStringRef);
18441846

18451847
pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef;
18461848

@@ -2046,6 +2048,30 @@ pub fn get_param(llfn: ValueRef, index: c_uint) -> ValueRef {
20462048
}
20472049
}
20482050

2051+
pub enum RustString_opaque {}
2052+
pub type RustStringRef = *mut RustString_opaque;
2053+
type RustStringRepr = *mut RefCell<Vec<u8>>;
2054+
2055+
/// Appending to a Rust string -- used by raw_rust_string_ostream.
2056+
#[no_mangle]
2057+
pub unsafe extern "C" fn rust_llvm_string_write_impl(sr: RustStringRef,
2058+
ptr: *const c_char,
2059+
size: size_t) {
2060+
let slice: &[u8] = mem::transmute(raw::Slice {
2061+
data: ptr as *const u8,
2062+
len: size as uint,
2063+
});
2064+
2065+
let sr: RustStringRepr = mem::transmute(sr);
2066+
(*sr).borrow_mut().push_all(slice);
2067+
}
2068+
2069+
pub fn build_string(f: |RustStringRef|) -> Option<String> {
2070+
let mut buf = RefCell::new(Vec::new());
2071+
f(&mut buf as RustStringRepr as RustStringRef);
2072+
String::from_utf8(buf.unwrap()).ok()
2073+
}
2074+
20492075
// FIXME #15460 - create a public function that actually calls our
20502076
// static LLVM symbols. Otherwise the linker will just throw llvm
20512077
// away. We're just calling lots of stuff until we transitively get

src/rustllvm/RustWrapper.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -645,22 +645,18 @@ extern "C" void LLVMDICompositeTypeSetTypeArray(
645645
#endif
646646
}
647647

648-
extern "C" char *LLVMTypeToString(LLVMTypeRef Type) {
649-
std::string s;
650-
llvm::raw_string_ostream os(s);
648+
extern "C" void LLVMWriteTypeToString(LLVMTypeRef Type, RustStringRef str) {
649+
raw_rust_string_ostream os(str);
651650
unwrap<llvm::Type>(Type)->print(os);
652-
return strdup(os.str().data());
653651
}
654652

655-
extern "C" char *LLVMValueToString(LLVMValueRef Value) {
656-
std::string s;
657-
llvm::raw_string_ostream os(s);
653+
extern "C" void LLVMWriteValueToString(LLVMValueRef Value, RustStringRef str) {
654+
raw_rust_string_ostream os(str);
658655
os << "(";
659656
unwrap<llvm::Value>(Value)->getType()->print(os);
660657
os << ":";
661658
unwrap<llvm::Value>(Value)->print(os);
662659
os << ")";
663-
return strdup(os.str().data());
664660
}
665661

666662
#if LLVM_VERSION_MINOR >= 5

src/rustllvm/rustllvm.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,31 @@
6969
#endif
7070

7171
void LLVMRustSetLastError(const char*);
72+
73+
typedef struct OpaqueRustString *RustStringRef;
74+
75+
extern "C" void
76+
rust_llvm_string_write_impl(RustStringRef str, const char *ptr, size_t size);
77+
78+
class raw_rust_string_ostream : public llvm::raw_ostream {
79+
RustStringRef str;
80+
uint64_t pos;
81+
82+
void write_impl(const char *ptr, size_t size) override {
83+
rust_llvm_string_write_impl(str, ptr, size);
84+
pos += size;
85+
}
86+
87+
uint64_t current_pos() const override {
88+
return pos;
89+
}
90+
91+
public:
92+
explicit raw_rust_string_ostream(RustStringRef str)
93+
: str(str), pos(0) { }
94+
95+
~raw_rust_string_ostream() {
96+
// LLVM requires this.
97+
flush();
98+
}
99+
};

0 commit comments

Comments
 (0)