From: Gordon Henriksen Date: Wed, 19 Dec 2007 22:30:40 +0000 (+0000) Subject: Adding bindings for memory buffers and module providers. Switching X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=da1435f86ebc9886dd7704294e01d192d79e069c Adding bindings for memory buffers and module providers. Switching to exceptions rather than variants for error handling in Ocaml. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@45226 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Xcode/LLVM.xcodeproj/project.pbxproj b/Xcode/LLVM.xcodeproj/project.pbxproj index 3920a8c77bb..8c7762e0cc9 100644 --- a/Xcode/LLVM.xcodeproj/project.pbxproj +++ b/Xcode/LLVM.xcodeproj/project.pbxproj @@ -98,6 +98,7 @@ 9F68EB130C77AD2C004AA152 /* BitcodeWriterPass.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = BitcodeWriterPass.cpp; sourceTree = ""; }; 9F68EB250C77AD2C004AA152 /* ValueEnumerator.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ValueEnumerator.cpp; sourceTree = ""; }; 9F68EB260C77AD2C004AA152 /* ValueEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ValueEnumerator.h; sourceTree = ""; }; + 9F6B2CC00D0F6E56000F00FD /* bitreader.ml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = bitreader.ml; sourceTree = ""; }; 9F7793460C73BC2000551F9C /* CodeGenPrepare.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeGenPrepare.cpp; sourceTree = ""; }; 9F7793470C73BC2000551F9C /* GVN.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GVN.cpp; sourceTree = ""; }; 9F7793480C73BC2000551F9C /* GVNPRE.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GVNPRE.cpp; sourceTree = ""; }; @@ -1241,6 +1242,7 @@ isa = PBXGroup; children = ( 9F7C2C4F0CB9496C00498408 /* analysis.ml */, + 9F6B2CC00D0F6E56000F00FD /* bitreader.ml */, 9F7C2C520CB9496C00498408 /* bitwriter.ml */, 9F7C2C5D0CB9496C00498408 /* vmcore.ml */, ); diff --git a/bindings/ocaml/analysis/analysis_ocaml.c b/bindings/ocaml/analysis/analysis_ocaml.c index c77fa73667f..9286b4cf7b0 100644 --- a/bindings/ocaml/analysis/analysis_ocaml.c +++ b/bindings/ocaml/analysis/analysis_ocaml.c @@ -37,7 +37,7 @@ CAMLprim value llvm_verify_module(LLVMModuleRef M) { Store_field(Option, 0, String); } - LLVMDisposeVerifierMessage(Message); + LLVMDisposeMessage(Message); CAMLreturn(Option); } diff --git a/bindings/ocaml/bitreader/bitreader_ocaml.c b/bindings/ocaml/bitreader/bitreader_ocaml.c index 7088fa5a478..87477f6312d 100644 --- a/bindings/ocaml/bitreader/bitreader_ocaml.c +++ b/bindings/ocaml/bitreader/bitreader_ocaml.c @@ -16,31 +16,46 @@ #include "caml/alloc.h" #include "caml/mlvalues.h" #include "caml/memory.h" +#include + + +/* Can't use the recommended caml_named_value mechanism for backwards + compatibility reasons. This is largely equivalent. */ +static value llvm_bitreader_error_exn; + +CAMLprim value llvm_register_bitreader_exns(value Error) { + llvm_bitreader_error_exn = Field(Error, 0); + register_global_root(&llvm_bitreader_error_exn); + return Val_unit; +} + +void llvm_raise(value Prototype, char *Message); + /*===-- Modules -----------------------------------------------------------===*/ -/* string -> bitreader_result +/* Llvm.llmemorybuffer -> Llvm.module */ +CAMLprim value llvm_get_module_provider(LLVMMemoryBufferRef MemBuf) { + CAMLparam0(); + CAMLlocal2(Variant, MessageVal); + char *Message; + + LLVMModuleProviderRef MP; + if (LLVMGetBitcodeModuleProvider(MemBuf, &MP, &Message)) + llvm_raise(llvm_bitreader_error_exn, Message); + + CAMLreturn((value) MemBuf); +} - type bitreader_result = - | Bitreader_success of Llvm.llmodule - | Bitreader_failure of string - */ -CAMLprim value llvm_read_bitcode_file(value Path) { +/* Llvm.llmemorybuffer -> Llvm.llmodule */ +CAMLprim value llvm_parse_bitcode(LLVMMemoryBufferRef MemBuf) { + CAMLparam0(); + CAMLlocal2(Variant, MessageVal); LLVMModuleRef M; char *Message; - CAMLparam1(Path); - CAMLlocal2(Variant, MessageVal); - if (LLVMReadBitcodeFromFile(String_val(Path), &M, &Message)) { - MessageVal = copy_string(Message); - LLVMDisposeBitcodeReaderMessage(Message); - - Variant = alloc(1, 1); - Field(Variant, 0) = MessageVal; - } else { - Variant = alloc(1, 0); - Field(Variant, 0) = Val_op(M); - } + if (LLVMParseBitcode(MemBuf, &M, &Message)) + llvm_raise(llvm_bitreader_error_exn, Message); - CAMLreturn(Variant); + CAMLreturn((value) M); } diff --git a/bindings/ocaml/bitreader/llvm_bitreader.ml b/bindings/ocaml/bitreader/llvm_bitreader.ml index 39d0434df7b..266ff153f31 100644 --- a/bindings/ocaml/bitreader/llvm_bitreader.ml +++ b/bindings/ocaml/bitreader/llvm_bitreader.ml @@ -8,10 +8,12 @@ *===----------------------------------------------------------------------===*) -type bitreader_result = -| Bitreader_success of Llvm.llmodule -| Bitreader_failure of string +exception Error of string +external register_exns : exn -> unit = "llvm_register_bitreader_exns" +let _ = register_exns (Error "") -external read_bitcode_file : string -> bitreader_result - = "llvm_read_bitcode_file" +external get_module_provider : Llvm.llmemorybuffer -> Llvm.llmoduleprovider + = "llvm_get_module_provider" +external parse_bitcode : Llvm.llmemorybuffer -> Llvm.llmodule + = "llvm_parse_bitcode" diff --git a/bindings/ocaml/bitreader/llvm_bitreader.mli b/bindings/ocaml/bitreader/llvm_bitreader.mli index 37750bcdb32..bc5efc880fb 100644 --- a/bindings/ocaml/bitreader/llvm_bitreader.mli +++ b/bindings/ocaml/bitreader/llvm_bitreader.mli @@ -13,13 +13,18 @@ *===----------------------------------------------------------------------===*) -type bitreader_result = -| Bitreader_success of Llvm.llmodule -| Bitreader_failure of string +exception Error of string +(** [read_bitcode_file path] reads the bitcode for a new module [m] from the + file at [path]. Returns [Success m] if successful, and [Failure msg] + otherwise, where [msg] is a description of the error encountered. + See the function [llvm::getBitcodeModuleProvider]. **) +external get_module_provider : Llvm.llmemorybuffer -> Llvm.llmoduleprovider + = "llvm_get_module_provider" -(** [read_bitcode_file path] reads the bitcode for module [m] from the file at - [path]. Returns [Reader_success m] if successful, and [Reader_failure msg] - otherwise, where [msg] is a description of the error encountered. **) -external read_bitcode_file : string -> bitreader_result - = "llvm_read_bitcode_file" +(** [parse_bitcode mb] parses the bitcode for a new module [m] from the memory + buffer [mb]. Returns [Success m] if successful, and [Failure msg] otherwise, + where [msg] is a description of the error encountered. + See the function [llvm::ParseBitcodeFile]. **) +external parse_bitcode : Llvm.llmemorybuffer -> Llvm.llmodule + = "llvm_parse_bitcode" diff --git a/bindings/ocaml/llvm/llvm.ml b/bindings/ocaml/llvm/llvm.ml index 5a5f4e7cfe1..58d9d5013e0 100644 --- a/bindings/ocaml/llvm/llvm.ml +++ b/bindings/ocaml/llvm/llvm.ml @@ -15,6 +15,7 @@ type llvalue type llbasicblock type llbuilder type llmoduleprovider +type llmemorybuffer type type_kind = Void_type @@ -84,6 +85,11 @@ type real_predicate = | Fcmp_une | Fcmp_true +exception IoError of string + +external register_exns : exn -> unit = "llvm_register_core_exns" +let _ = register_exns (IoError "") + (*===-- Modules -----------------------------------------------------------===*) @@ -432,10 +438,21 @@ external build_shufflevector : llvalue -> llvalue -> llvalue -> string -> (*===-- Module providers --------------------------------------------------===*) -external create_module_provider : llmodule -> llmoduleprovider - = "LLVMCreateModuleProviderForExistingModule" -external dispose_module_provider : llmoduleprovider -> unit - = "llvm_dispose_module_provider" + +module ModuleProvider = struct + external create : llmodule -> llmoduleprovider + = "LLVMCreateModuleProviderForExistingModule" + external dispose : llmoduleprovider -> unit = "llvm_dispose_module_provider" +end + + +(*===-- Memory buffers ----------------------------------------------------===*) + +module MemoryBuffer = struct + external of_file : string -> llmemorybuffer = "llvm_memorybuffer_of_file" + external of_stdin : unit -> llmemorybuffer = "llvm_memorybuffer_of_stdin" + external dispose : llmemorybuffer -> unit = "llvm_memorybuffer_dispose" +end (*===-- Non-Externs -------------------------------------------------------===*) diff --git a/bindings/ocaml/llvm/llvm.mli b/bindings/ocaml/llvm/llvm.mli index 4646c576152..546ab4579fe 100644 --- a/bindings/ocaml/llvm/llvm.mli +++ b/bindings/ocaml/llvm/llvm.mli @@ -40,9 +40,14 @@ type llbasicblock class. **) type llbuilder -(** Used to provide a module to JIT or interpreter. **) +(** Used to provide a module to JIT or interpreter. + See the [llvm::ModuleProvider] class. **) type llmoduleprovider +(** Used to efficiently handle large buffers of read-only binary data. + See the [llvm::MemoryBuffer] class. **) +type llmemorybuffer + (** The kind of an [lltype], the result of [classify_type ty]. See the [llvm::Type::TypeID] enumeration. **) type type_kind = @@ -129,6 +134,8 @@ type real_predicate = | Fcmp_une | Fcmp_true +exception IoError of string + (*===-- Modules -----------------------------------------------------------===*) @@ -1235,13 +1242,30 @@ external build_shufflevector : llvalue -> llvalue -> llvalue -> string -> (*===-- Module providers --------------------------------------------------===*) -(** [create_module_provider m] encapsulates [m] in a module provider and takes - ownership of the module. See the constructor - [llvm::ExistingModuleProvider::ExistingModuleProvider]. **) -external create_module_provider : llmodule -> llmoduleprovider - = "LLVMCreateModuleProviderForExistingModule" - -(** [dispose_module_provider mp] destroys the module provider [mp] as well as - the contained module. **) -external dispose_module_provider : llmoduleprovider -> unit - = "llvm_dispose_module_provider" +module ModuleProvider : sig + (** [create_module_provider m] encapsulates [m] in a module provider and takes + ownership of the module. See the constructor + [llvm::ExistingModuleProvider::ExistingModuleProvider]. **) + external create : llmodule -> llmoduleprovider + = "LLVMCreateModuleProviderForExistingModule" + + (** [dispose_module_provider mp] destroys the module provider [mp] as well as + the contained module. **) + external dispose : llmoduleprovider -> unit = "llvm_dispose_module_provider" +end + + +(*===-- Memory buffers ----------------------------------------------------===*) + +module MemoryBuffer : sig + (** [of_file p] is the memory buffer containing the contents of the file at + path [p]. If the file could not be read, then [IoError msg] is raised. **) + external of_file : string -> llmemorybuffer = "llvm_memorybuffer_of_file" + + (** [stdin ()] is the memory buffer containing the contents of standard input. + If standard input is empty, then [IoError msg] is raised. **) + external of_stdin : unit -> llmemorybuffer = "llvm_memorybuffer_of_stdin" + + (** Disposes of a memory buffer. **) + external dispose : llmemorybuffer -> unit = "llvm_memorybuffer_dispose" +end diff --git a/bindings/ocaml/llvm/llvm_ocaml.c b/bindings/ocaml/llvm/llvm_ocaml.c index 43b6167bdc0..5cd9526f560 100644 --- a/bindings/ocaml/llvm/llvm_ocaml.c +++ b/bindings/ocaml/llvm/llvm_ocaml.c @@ -20,8 +20,33 @@ #include "caml/custom.h" #include "caml/mlvalues.h" #include "caml/memory.h" +#include "caml/fail.h" +#include "caml/callback.h" #include "llvm/Config/config.h" #include +#include + + +/* Can't use the recommended caml_named_value mechanism for backwards + compatibility reasons. This is largely equivalent. */ +static value llvm_ioerror_exn; + +CAMLprim value llvm_register_core_exns(value IoError) { + llvm_ioerror_exn = Field(IoError, 0); + register_global_root(&llvm_ioerror_exn); + return Val_unit; +} + +void llvm_raise(value Prototype, char *Message) { + CAMLparam1(Prototype); + CAMLlocal1(CamlMessage); + + CamlMessage = copy_string(Message); + LLVMDisposeMessage(Message); + + raise_with_arg(Prototype, CamlMessage); + CAMLnoreturn; +} /*===-- Modules -----------------------------------------------------------===*/ @@ -1071,3 +1096,39 @@ CAMLprim value llvm_dispose_module_provider(LLVMModuleProviderRef MP) { LLVMDisposeModuleProvider(MP); return Val_unit; } + + +/*===-- Memory buffers ----------------------------------------------------===*/ + +/* string -> llmemorybuffer + raises IoError msg on error */ +CAMLprim value llvm_memorybuffer_of_file(value Path) { + CAMLparam1(Path); + char *Message; + LLVMMemoryBufferRef MemBuf; + + if (LLVMCreateMemoryBufferWithContentsOfFile(String_val(Path), + &MemBuf, &Message)) + llvm_raise(llvm_ioerror_exn, Message); + + CAMLreturn((value) MemBuf); +} + +/* unit -> llmemorybuffer + raises IoError msg on error */ +CAMLprim LLVMMemoryBufferRef llvm_memorybuffer_of_stdin(value Unit) { + char *Message; + LLVMMemoryBufferRef MemBuf; + + if (LLVMCreateMemoryBufferWithSTDIN(&MemBuf, &Message)) + llvm_raise(llvm_ioerror_exn, Message); + + return MemBuf; +} + +/* llmemorybuffer -> unit */ +CAMLprim value llvm_memorybuffer_dispose(LLVMMemoryBufferRef MemBuf) { + LLVMDisposeMemoryBuffer(MemBuf); + return Val_unit; +} + diff --git a/include/llvm-c/Analysis.h b/include/llvm-c/Analysis.h index b57577b0588..f93e18aeca7 100644 --- a/include/llvm-c/Analysis.h +++ b/include/llvm-c/Analysis.h @@ -34,13 +34,11 @@ typedef enum { /* Verifies that a module is valid, taking the specified action if not. - Optionally returns a human-readable description of any invalid constructs. */ + Optionally returns a human-readable description of any invalid constructs. + OutMessage must be disposed with LLVMDisposeMessage. */ int LLVMVerifyModule(LLVMModuleRef M, LLVMVerifierFailureAction Action, char **OutMessage); -/* Disposes of the message allocated by the verifier, if any. */ -void LLVMDisposeVerifierMessage(char *Message); - /* Verifies that a single function is valid, taking the specified action. Useful for debugging. */ int LLVMVerifyFunction(LLVMValueRef Fn, LLVMVerifierFailureAction Action); diff --git a/include/llvm-c/BitReader.h b/include/llvm-c/BitReader.h index ba77988a743..f821d686708 100644 --- a/include/llvm-c/BitReader.h +++ b/include/llvm-c/BitReader.h @@ -26,21 +26,18 @@ extern "C" { #endif -/* Reads a module from the specified path, returning a reference to the module - via the OutModule parameter. Returns 0 on success. Optionally returns a - human-readable error message. */ -int LLVMReadBitcodeFromFile(const char *Path, LLVMModuleRef *OutModule, - char **OutMessage); - -/* Reads a module from the specified path, returning a reference to a lazy - module provider via the OutModule parameter. Returns 0 on success. Optionally - returns a human-readable error message. */ -int LLVMCreateModuleProviderFromFile(const char *Path, - LLVMModuleProviderRef *OutMP, - char **OutMessage); - -/* Disposes of the message allocated by the bitcode reader, if any. */ -void LLVMDisposeBitcodeReaderMessage(char *Message); +/* Builds a module from the bitcode in the specified memory buffer, returning a + reference to the module via the OutModule parameter. Returns 0 on success. + Optionally returns a human-readable error message via OutMessage. */ +int LLVMParseBitcode(LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutModule, char **OutMessage); + +/* Reads a module from the specified path, returning via the OutMP parameter + a module provider which performs lazy deserialization. Returns 0 on success. + Optionally returns a human-readable error message via OutMessage. */ +int LLVMGetBitcodeModuleProvider(LLVMMemoryBufferRef MemBuf, + LLVMModuleProviderRef *OutMP, + char **OutMessage); #ifdef __cplusplus diff --git a/include/llvm-c/Core.h b/include/llvm-c/Core.h index 4ed2bd0c60d..e2165721534 100644 --- a/include/llvm-c/Core.h +++ b/include/llvm-c/Core.h @@ -51,8 +51,17 @@ typedef struct LLVMOpaqueTypeHandle *LLVMTypeHandleRef; typedef struct LLVMOpaqueValue *LLVMValueRef; typedef struct LLVMOpaqueBasicBlock *LLVMBasicBlockRef; typedef struct LLVMOpaqueBuilder *LLVMBuilderRef; + +/* Used to provide a module to JIT or interpreter. + * See the llvm::ModuleProvider class. + */ typedef struct LLVMOpaqueModuleProvider *LLVMModuleProviderRef; +/* Used to provide a module to JIT or interpreter. + * See the llvm::MemoryBuffer class. + */ +typedef struct LLVMOpaqueMemoryBuffer *LLVMMemoryBufferRef; + typedef enum { LLVMVoidTypeKind, /* type with no size */ LLVMFloatTypeKind, /* 32 bit floating point type */ @@ -129,6 +138,11 @@ typedef enum { } LLVMRealPredicate; +/*===-- Error handling ----------------------------------------------------===*/ + +void LLVMDisposeMessage(char *Message); + + /*===-- Modules -----------------------------------------------------------===*/ /* Create and destroy modules. */ @@ -491,6 +505,7 @@ LLVMValueRef LLVMBuildShuffleVector(LLVMBuilderRef, LLVMValueRef V1, LLVMValueRef V2, LLVMValueRef Mask, const char *Name); + /*===-- Module providers --------------------------------------------------===*/ /* Encapsulates the module M in a module provider, taking ownership of the @@ -505,28 +520,45 @@ LLVMCreateModuleProviderForExistingModule(LLVMModuleRef M); */ void LLVMDisposeModuleProvider(LLVMModuleProviderRef MP); + +/*===-- Memory buffers ----------------------------------------------------===*/ + +int LLVMCreateMemoryBufferWithContentsOfFile(const char *Path, + LLVMMemoryBufferRef *OutMemBuf, + char **OutMessage); +int LLVMCreateMemoryBufferWithSTDIN(LLVMMemoryBufferRef *OutMemBuf, + char **OutMessage); +void LLVMDisposeMemoryBuffer(LLVMMemoryBufferRef MemBuf); + #ifdef __cplusplus } namespace llvm { class ModuleProvider; + class MemoryBuffer; - /* Opaque module conversions - */ - inline Module *unwrap(LLVMModuleRef M) { - return reinterpret_cast(M); - } + #define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \ + inline ty *unwrap(ref P) { \ + return reinterpret_cast(P); \ + } \ + \ + inline ref wrap(const ty *P) { \ + return reinterpret_cast(const_cast(P)); \ + } - inline LLVMModuleRef wrap(Module *M) { - return reinterpret_cast(M); - } + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Type, LLVMTypeRef ) + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Value, LLVMValueRef ) + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Module, LLVMModuleRef ) + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(BasicBlock, LLVMBasicBlockRef ) + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMBuilder, LLVMBuilderRef ) + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(PATypeHolder, LLVMTypeHandleRef ) + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ModuleProvider, LLVMModuleProviderRef) + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(MemoryBuffer, LLVMMemoryBufferRef ) - /* Opaque type conversions - */ - inline Type *unwrap(LLVMTypeRef Ty) { - return reinterpret_cast(Ty); - } + #undef DEFINE_SIMPLE_CONVERSION_FUNCTIONS + /* Specialized opaque type conversions. + */ template inline T *unwrap(LLVMTypeRef Ty) { return cast(unwrap(Ty)); @@ -536,20 +568,12 @@ namespace llvm { return reinterpret_cast(Tys); } - inline LLVMTypeRef wrap(const Type *Ty) { - return reinterpret_cast(const_cast(Ty)); - } - inline LLVMTypeRef *wrap(const Type **Tys) { return reinterpret_cast(const_cast(Tys)); } - /* Opaque value conversions + /* Specialized opaque value conversions. */ - inline Value *unwrap(LLVMValueRef Val) { - return reinterpret_cast(Val); - } - template inline T *unwrap(LLVMValueRef Val) { return cast(unwrap(Val)); @@ -568,53 +592,9 @@ namespace llvm { return reinterpret_cast(Vals); } - inline LLVMValueRef wrap(const Value *Val) { - return reinterpret_cast(const_cast(Val)); - } - inline LLVMValueRef *wrap(const Value **Vals) { return reinterpret_cast(const_cast(Vals)); } - - /* Basic block conversions - */ - inline BasicBlock *unwrap(LLVMBasicBlockRef BBRef) { - return reinterpret_cast(BBRef); - } - - inline LLVMBasicBlockRef wrap(const BasicBlock *BB) { - return reinterpret_cast(const_cast(BB)); - } - - /* Opaque builder conversions. - */ - inline LLVMBuilder *unwrap(LLVMBuilderRef B) { - return reinterpret_cast(B); - } - - inline LLVMBuilderRef wrap(LLVMBuilder *B) { - return reinterpret_cast(B); - } - - /* Opaque type handle conversions. - */ - inline PATypeHolder *unwrap(LLVMTypeHandleRef B) { - return reinterpret_cast(B); - } - - inline LLVMTypeHandleRef wrap(PATypeHolder *B) { - return reinterpret_cast(B); - } - - /* Opaque module provider conversions. - */ - inline ModuleProvider *unwrap(LLVMModuleProviderRef P) { - return reinterpret_cast(P); - } - - inline LLVMModuleProviderRef wrap(ModuleProvider *P) { - return reinterpret_cast(P); - } } #endif /* !defined(__cplusplus) */ diff --git a/lib/Analysis/Analysis.cpp b/lib/Analysis/Analysis.cpp index 6403f2d7faf..685c754ff60 100644 --- a/lib/Analysis/Analysis.cpp +++ b/lib/Analysis/Analysis.cpp @@ -27,10 +27,6 @@ int LLVMVerifyModule(LLVMModuleRef M, LLVMVerifierFailureAction Action, return Result; } -void LLVMDisposeVerifierMessage(char *Message) { - free(Message); -} - int LLVMVerifyFunction(LLVMValueRef Fn, LLVMVerifierFailureAction Action) { return verifyFunction(*unwrap(Fn), static_cast(Action)); diff --git a/lib/Bitcode/Reader/BitReader.cpp b/lib/Bitcode/Reader/BitReader.cpp index c6600887bc4..c7c38690c5a 100644 --- a/lib/Bitcode/Reader/BitReader.cpp +++ b/lib/Bitcode/Reader/BitReader.cpp @@ -14,20 +14,33 @@ using namespace llvm; - -int LLVMReadBitcodeFromFile(const char *Path, LLVMModuleRef *OutModule, - char **OutMessage) { +/* Builds a module from the bitcode in the specified memory buffer, returning a + reference to the module via the OutModule parameter. Returns 0 on success. + Optionally returns a human-readable error message via OutMessage. */ +int LLVMParseBitcode(LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutModule, char **OutMessage) { std::string Message; - MemoryBuffer *buf = MemoryBuffer::getFile(Path, strlen(Path), &Message); - if (!buf) { - if (!OutMessage) + *OutModule = wrap(ParseBitcodeFile(unwrap(MemBuf), &Message)); + if (!*OutModule) { + if (OutMessage) *OutMessage = strdup(Message.c_str()); return 1; } - *OutModule = wrap(ParseBitcodeFile(buf, &Message)); - if (!*OutModule) { + return 0; +} + +/* Reads a module from the specified path, returning via the OutModule parameter + a module provider which performs lazy deserialization. Returns 0 on success. + Optionally returns a human-readable error message via OutMessage. */ +int LLVMGetBitcodeModuleProvider(LLVMMemoryBufferRef MemBuf, + LLVMModuleProviderRef *OutMP, + char **OutMessage) { + std::string Message; + + *OutMP = wrap(getBitcodeModuleProvider(unwrap(MemBuf), &Message)); + if (!*OutMP) { if (OutMessage) *OutMessage = strdup(Message.c_str()); return 1; @@ -35,8 +48,3 @@ int LLVMReadBitcodeFromFile(const char *Path, LLVMModuleRef *OutModule, return 0; } - -void LLVMDisposeBitcodeReaderMessage(char *Message) { - if (Message) - free(Message); -} diff --git a/lib/VMCore/Core.cpp b/lib/VMCore/Core.cpp index 4c56e556eb3..2b54fb31525 100644 --- a/lib/VMCore/Core.cpp +++ b/lib/VMCore/Core.cpp @@ -19,11 +19,20 @@ #include "llvm/GlobalVariable.h" #include "llvm/TypeSymbolTable.h" #include "llvm/ModuleProvider.h" +#include "llvm/Support/MemoryBuffer.h" #include +#include using namespace llvm; +/*===-- Error handling ----------------------------------------------------===*/ + +void LLVMDisposeMessage(char *Message) { + free(Message); +} + + /*===-- Operations on modules ---------------------------------------------===*/ LLVMModuleRef LLVMModuleCreateWithName(const char *ModuleID) { @@ -1048,3 +1057,33 @@ void LLVMDisposeModuleProvider(LLVMModuleProviderRef MP) { delete unwrap(MP); } + +/*===-- Memory buffers ----------------------------------------------------===*/ + +int LLVMCreateMemoryBufferWithContentsOfFile(const char *Path, + LLVMMemoryBufferRef *OutMemBuf, + char **OutMessage) { + std::string Error; + if (MemoryBuffer *MB = MemoryBuffer::getFile(Path, strlen(Path), &Error)) { + *OutMemBuf = wrap(MB); + return 0; + } + + *OutMessage = strdup(Error.c_str()); + return 1; +} + +int LLVMCreateMemoryBufferWithSTDIN(LLVMMemoryBufferRef *OutMemBuf, + char **OutMessage) { + if (MemoryBuffer *MB = MemoryBuffer::getSTDIN()) { + *OutMemBuf = wrap(MB); + return 0; + } + + *OutMessage = strdup("stdin is empty."); + return 1; +} + +void LLVMDisposeMemoryBuffer(LLVMMemoryBufferRef MemBuf) { + delete unwrap(MemBuf); +} diff --git a/test/Bindings/Ocaml/bitreader.ml b/test/Bindings/Ocaml/bitreader.ml index 0bf8c00bc1f..05bbd28e06f 100644 --- a/test/Bindings/Ocaml/bitreader.ml +++ b/test/Bindings/Ocaml/bitreader.ml @@ -18,6 +18,58 @@ let _ = Llvm.dispose_module m; - test (match Llvm_bitreader.read_bitcode_file fn with - | Llvm_bitreader.Bitreader_success m -> Llvm.dispose_module m; true - | Llvm_bitreader.Bitreader_failure _ -> false) + (* parse_bitcode *) + begin + let mb = Llvm.MemoryBuffer.of_file fn in + begin try + let m = Llvm_bitreader.parse_bitcode mb in + Llvm.dispose_module m + with x -> + Llvm.MemoryBuffer.dispose; + raise x + end + end; + + (* MemoryBuffer.of_file *) + test begin try + let mb = Llvm.MemoryBuffer.of_file (fn ^ ".bogus") in + Llvm.MemoryBuffer.dispose mb; + false + with Llvm.IoError _ -> + true + end; + + (* get_module_provider *) + begin + let mb = Llvm.MemoryBuffer.of_file fn in + let mp = begin try + Llvm_bitreader.get_module_provider mb + with x -> + Llvm.MemoryBuffer.dispose mb; + raise x + end in + Llvm.ModuleProvider.dispose mp + end; + + (* corrupt the bitcode *) + let fn = fn ^ ".txt" in + begin let oc = open_out fn in + output_string oc "not a bitcode file\n"; + close_out oc + end; + + (* test get_module_provider exceptions *) + test begin + try + let mb = Llvm.MemoryBuffer.of_file fn in + let mp = begin try + Llvm_bitreader.get_module_provider mb + with x -> + Llvm.MemoryBuffer.dispose mb; + raise x + end in + Llvm.ModuleProvider.dispose mp; + false + with Llvm_bitreader.Error _ -> + true + end diff --git a/test/Bindings/Ocaml/vmcore.ml b/test/Bindings/Ocaml/vmcore.ml index 65d8a316e9c..04b80868c4d 100644 --- a/test/Bindings/Ocaml/vmcore.ml +++ b/test/Bindings/Ocaml/vmcore.ml @@ -805,8 +805,8 @@ let test_builder () = let test_module_provider () = let m = create_module "test" in - let mp = create_module_provider m in - dispose_module_provider mp + let mp = ModuleProvider.create m in + ModuleProvider.dispose mp (*===-- Writer ------------------------------------------------------------===*)