Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 146 additions & 14 deletions runtime/src/iree/base/status.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,6 @@ IREE_API_EXPORT const char* iree_status_code_string(iree_status_code_t code) {
}
}

// TODO(#55): move payload methods/types to header when API is stabilized.

struct iree_status_handle_t {
uintptr_t value;
};
Expand Down Expand Up @@ -547,6 +545,77 @@ IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t iree_status_allocate_vf(
format, varargs_0, varargs_1);
}

IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t
iree_status_allocate_copy(iree_status_code_t code, iree_string_view_t file,
uint32_t line, iree_string_view_t message) {
#if IREE_STATUS_FEATURES == 0
return iree_status_from_code(code);
#else
if (IREE_UNLIKELY(code == IREE_STATUS_OK)) return iree_ok_status();

// Compute layout: storage + file string (NUL-terminated) + message string.
iree_host_size_t unaligned_size = 0;
iree_host_size_t file_offset = 0;
iree_host_size_t message_offset = 0;

// File string with NUL terminator (if present).
bool has_file = file.size > 0;
iree_host_size_t file_alloc_size = 0;
if (has_file && !iree_host_size_checked_add(file.size, 1, &file_alloc_size)) {
return iree_status_from_code(code);
}
// Message with NUL terminator (if present).
bool has_message = message.size > 0;
iree_host_size_t message_alloc_size = 0;
if (has_message &&
!iree_host_size_checked_add(message.size, 1, &message_alloc_size)) {
return iree_status_from_code(code);
}

iree_status_t layout_status = IREE_STRUCT_LAYOUT(
iree_sizeof_struct(iree_status_storage_t), &unaligned_size,
IREE_STRUCT_FIELD(file_alloc_size, char, &file_offset),
IREE_STRUCT_FIELD(message_alloc_size, char, &message_offset));
if (!iree_status_is_ok(layout_status)) {
iree_status_ignore(layout_status);
return iree_status_from_code(code);
}

iree_host_size_t storage_alignment = (IREE_STATUS_CODE_MASK + 1);
iree_host_size_t storage_size = 0;
if (!iree_host_size_checked_align(unaligned_size, storage_alignment,
&storage_size)) {
return iree_status_from_code(code);
}
iree_status_storage_t* storage =
(iree_status_storage_t*)iree_aligned_alloc_raw(storage_alignment,
storage_size);
if (IREE_UNLIKELY(!storage)) return iree_status_from_code(code);
memset(storage, 0, sizeof(*storage));

#if (IREE_STATUS_FEATURES & IREE_STATUS_FEATURE_SOURCE_LOCATION) != 0
if (has_file) {
char* file_copy = (char*)storage + file_offset;
memcpy(file_copy, file.data, file.size);
file_copy[file.size] = '\0';
storage->file = file_copy;
}
storage->line = line;
#endif // has IREE_STATUS_FEATURE_SOURCE_LOCATION

#if (IREE_STATUS_FEATURES & IREE_STATUS_FEATURE_ANNOTATIONS) != 0
if (has_message) {
char* message_copy = (char*)storage + message_offset;
memcpy(message_copy, message.data, message.size);
message_copy[message.size] = '\0';
storage->message = iree_make_string_view(message_copy, message.size);
}
#endif // has IREE_STATUS_FEATURE_ANNOTATIONS

return (iree_status_t)((uintptr_t)storage | (code & IREE_STATUS_CODE_MASK));
#endif // has any IREE_STATUS_FEATURES
}

IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t
iree_status_clone(iree_status_t status) {
#if IREE_STATUS_FEATURES == 0
Expand All @@ -556,24 +625,25 @@ iree_status_clone(iree_status_t status) {
iree_status_storage_t* storage = iree_status_storage(status);
if (!storage) return status;

#if (IREE_STATUS_FEATURES & IREE_STATUS_FEATURE_SOURCE_LOCATION) != 0
const char* file = storage->file;
uint32_t line = storage->line;
#else
const char* file = NULL;
iree_string_view_t file = iree_string_view_empty();
uint32_t line = 0;
#if (IREE_STATUS_FEATURES & IREE_STATUS_FEATURE_SOURCE_LOCATION) != 0
if (storage->file) {
file = iree_make_cstring_view(storage->file);
}
line = storage->line;
#endif // has IREE_STATUS_FEATURE_SOURCE_LOCATION

#if (IREE_STATUS_FEATURES & IREE_STATUS_FEATURE_ANNOTATIONS) != 0
iree_string_view_t message = storage->message;
#else
iree_string_view_t message = iree_string_view_empty();
#if (IREE_STATUS_FEATURES & IREE_STATUS_FEATURE_ANNOTATIONS) != 0
message = storage->message;
#endif // has IREE_STATUS_FEATURE_ANNOTATIONS

// Always copy the message by performing the formatting as we don't know
// whether the original status has ownership or not.
return iree_status_allocate_f(iree_status_code(status), file, line, "%.*s",
(int)message.size, message.data);
// Copy both file and message into self-contained storage. The original
// status may borrow these pointers from rodata (__FILE__) or from
// trailing storage that will be freed, so we always copy.
return iree_status_allocate_copy(iree_status_code(status), file, line,
message);
#endif // has no IREE_STATUS_FEATURES
}

Expand Down Expand Up @@ -994,6 +1064,68 @@ IREE_API_EXPORT bool iree_status_to_string(
}
}

//===----------------------------------------------------------------------===//
// Status structured access
//===----------------------------------------------------------------------===//

IREE_API_EXPORT iree_status_source_location_t
iree_status_source_location(iree_status_t status) {
iree_status_source_location_t location = {NULL, 0};
#if (IREE_STATUS_FEATURES & IREE_STATUS_FEATURE_SOURCE_LOCATION) != 0
iree_status_storage_t* storage = iree_status_storage(status);
if (storage) {
location.file = storage->file;
location.line = storage->line;
}
#endif // has IREE_STATUS_FEATURE_SOURCE_LOCATION
return location;
}

IREE_API_EXPORT iree_string_view_t iree_status_message(iree_status_t status) {
#if (IREE_STATUS_FEATURES & IREE_STATUS_FEATURE_ANNOTATIONS) != 0
iree_status_storage_t* storage = iree_status_storage(status);
if (storage) {
return storage->message;
}
#endif // has IREE_STATUS_FEATURE_ANNOTATIONS
return iree_string_view_empty();
}

IREE_API_EXPORT iree_status_t iree_status_enumerate_payloads(
iree_status_t status, iree_status_payload_visitor_fn_t visitor,
void* user_data) {
#if IREE_STATUS_FEATURES != 0
iree_status_storage_t* storage = iree_status_storage(status);
if (!storage) return iree_ok_status();
iree_status_payload_t* payload = storage->payload_head;
while (payload) {
iree_status_t visit_status = visitor(user_data, payload);
if (!iree_status_is_ok(visit_status)) return visit_status;
payload = payload->next;
}
#endif // has any IREE_STATUS_FEATURES
return iree_ok_status();
}

IREE_API_EXPORT iree_status_payload_type_t
iree_status_payload_type(const iree_status_payload_t* payload) {
return payload->type;
}

IREE_API_EXPORT void iree_status_payload_format(
const iree_status_payload_t* payload, iree_host_size_t buffer_capacity,
char* buffer, iree_host_size_t* out_buffer_length) {
if (!payload->formatter) {
if (out_buffer_length) *out_buffer_length = 0;
return;
}
payload->formatter(payload, buffer_capacity, buffer, out_buffer_length);
}

//===----------------------------------------------------------------------===//
// Status printing
//===----------------------------------------------------------------------===//

IREE_API_EXPORT void iree_status_fprint(FILE* file, iree_status_t status) {
// TODO(benvanik): better support for colors/etc - possibly move to logging.
// TODO(benvanik): do this without allocation by streaming the status.
Expand Down
87 changes: 87 additions & 0 deletions runtime/src/iree/base/status.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ extern "C" {
#endif // __cplusplus

typedef struct iree_allocator_t iree_allocator_t;
typedef struct iree_status_payload_t iree_status_payload_t;

//===----------------------------------------------------------------------===//
// IREE_STATUS_FEATURE flags and IREE_STATUS_MODE setting
Expand Down Expand Up @@ -451,6 +452,15 @@ IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t iree_status_allocate_vf(
iree_status_code_t code, const char* file, uint32_t line,
const char* format, va_list varargs_0, va_list varargs_1);

// Like iree_status_allocate but copies both |file| and |message| into the
// status storage, making the status self-contained. Normal status allocation
// stores |file| as a borrowed pointer (expected to be a __FILE__ string literal
// with static lifetime); this variant is for cases where that assumption does
// not hold, such as deserializing a status from a wire format.
IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t
iree_status_allocate_copy(iree_status_code_t code, iree_string_view_t file,
uint32_t line, iree_string_view_t message);

// Clones |status| into a new status instance.
// No payloads, if present, will be cloned.
IREE_API_EXPORT IREE_MUST_USE_RESULT iree_status_t
Expand Down Expand Up @@ -554,6 +564,83 @@ IREE_API_EXPORT bool iree_status_to_string(iree_status_t status,
// only when dumping a status on failure.
IREE_API_EXPORT void iree_status_fprint(FILE* file, iree_status_t status);

//===----------------------------------------------------------------------===//
// Status payload types
//===----------------------------------------------------------------------===//

// Defines the type of an iree_status_payload_t.
typedef enum iree_status_payload_type_e {
// Opaque; payload may still be formatted by a formatter but is not possible
// to retrieve by the programmatic APIs.
IREE_STATUS_PAYLOAD_TYPE_OPAQUE = 0,
// A string message annotation.
IREE_STATUS_PAYLOAD_TYPE_MESSAGE = 1,
// Platform-dependent stack trace.
IREE_STATUS_PAYLOAD_TYPE_STACK_TRACE = 2,
// Starting type ID for user payloads. IREE reserves all payloads with types
// less than this.
IREE_STATUS_PAYLOAD_TYPE_MIN_USER = 0x70000000u,
} iree_status_payload_type_t;

//===----------------------------------------------------------------------===//
// Status structured access
//===----------------------------------------------------------------------===//

// Source location of a status allocation.
typedef struct iree_status_source_location_t {
// Source filename (__FILE__), or NULL if not available.
// Points into the status storage — valid only while the status is alive.
const char* file;
// Source line number (__LINE__), or 0 if not available.
uint32_t line;
} iree_status_source_location_t;

// Returns the source location where |status| was allocated.
// Returns {NULL, 0} for OK statuses or when IREE_STATUS_FEATURE_SOURCE_LOCATION
// is disabled.
IREE_API_EXPORT iree_status_source_location_t
iree_status_source_location(iree_status_t status);

// Returns the primary message of |status| (the message from the original
// iree_status_allocate or iree_make_status call, not including annotations).
// Returns an empty string view for OK statuses or when
// IREE_STATUS_FEATURE_ANNOTATIONS is disabled.
//
// The returned string view points into the status storage and is valid only
// while the status is alive.
IREE_API_EXPORT iree_string_view_t iree_status_message(iree_status_t status);

// Payload visitor callback. Called once for each payload attached to a status.
// |payload| is valid only for the duration of the callback. Return a non-OK
// status to stop enumeration early.
typedef iree_status_t (*iree_status_payload_visitor_fn_t)(
void* user_data, const iree_status_payload_t* payload);

// Enumerates all payloads attached to |status|, calling |visitor| for each.
// Payloads are visited in the order they were attached (oldest first).
// Enumeration stops early if |visitor| returns a non-OK status, which is
// propagated as the return value.
//
// Returns iree_ok_status() for OK statuses or statuses with no payloads.
IREE_API_EXPORT iree_status_t iree_status_enumerate_payloads(
iree_status_t status, iree_status_payload_visitor_fn_t visitor,
void* user_data);

// Returns the type of |payload|.
IREE_API_EXPORT iree_status_payload_type_t
iree_status_payload_type(const iree_status_payload_t* payload);

// Formats |payload| into a human-readable string. Follows the standard
// two-pass pattern: call with buffer_capacity=0/buffer=NULL to query the
// required length, then call again with a sufficiently sized buffer.
//
// Sets |*out_buffer_length| to the number of characters written (or required),
// excluding NUL. Sets |*out_buffer_length| to 0 if the payload has no
// formatter.
IREE_API_EXPORT void iree_status_payload_format(
const iree_status_payload_t* payload, iree_host_size_t buffer_capacity,
char* buffer, iree_host_size_t* out_buffer_length);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
Expand Down
22 changes: 3 additions & 19 deletions runtime/src/iree/base/status_payload.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,12 @@ extern "C" {
#endif // __cplusplus

//===----------------------------------------------------------------------===//
// Status payload API
// Status payload internals
//===----------------------------------------------------------------------===//

typedef struct iree_status_storage_t iree_status_storage_t;

// Defines the type of an iree_status_payload_t.
typedef enum iree_status_payload_type_e {
// Opaque; payload may still be formatted by a formatter but is not possible
// to retrieve by the programmatic APIs.
IREE_STATUS_PAYLOAD_TYPE_OPAQUE = 0,
// A string message annotation of type iree_status_payload_message_t.
IREE_STATUS_PAYLOAD_TYPE_MESSAGE = 1,
// Platform-dependent stack trace in iree_status_payload_stack_trace_t.
IREE_STATUS_PAYLOAD_TYPE_STACK_TRACE = 2,
// Starting type ID for user payloads. IREE reserves all payloads with types
// less than this.
IREE_STATUS_PAYLOAD_TYPE_MIN_USER = 0x70000000u,
} iree_status_payload_type_t;
// iree_status_payload_type_t is defined in status.h (public API).

typedef struct iree_status_payload_t iree_status_payload_t;
typedef struct iree_status_storage_t iree_status_storage_t;

// Function that formats a payload into a human-readable string form for logs.
typedef void(IREE_API_PTR* iree_status_payload_formatter_t)(
Expand Down Expand Up @@ -75,8 +61,6 @@ typedef struct iree_status_payload_stack_trace_t {
uintptr_t addresses[];
} iree_status_payload_stack_trace_t;

// TODO(benvanik): expose API for appending/enumerating payloads.
// Currently this is an implementation detail.
iree_status_t iree_status_append_payload(iree_status_t status,
iree_status_storage_t* storage,
iree_status_payload_t* payload);
Expand Down
Loading