blob: 058002fa093e564998dcd62ca3a0121ddbb3397e [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* \file src/ffi/error.cc
* \brief Error handling implementation
*/
#include <tvm/ffi/base_details.h>
#include <tvm/ffi/c_api.h>
#include <tvm/ffi/error.h>
#include <cstring>
namespace tvm {
namespace ffi {
class SafeCallContext {
public:
void SetRaised(TVMFFIObjectHandle error) {
last_error_ =
details::ObjectUnsafe::ObjectPtrFromUnowned<ErrorObj>(static_cast<TVMFFIObject*>(error));
}
void SetRaisedByCstr(const char* kind, const char* message, const TVMFFIByteArray* backtrace) {
Error error(kind, message, backtrace);
last_error_ = details::ObjectUnsafe::ObjectPtrFromObjectRef<ErrorObj>(std::move(error));
}
void SetRaisedByCstrParts(const char* kind, const char** message_parts, int32_t num_parts,
const TVMFFIByteArray* backtrace) {
std::string message;
size_t total_len = 0;
for (int i = 0; i < num_parts; ++i) {
if (message_parts[i] != nullptr) {
total_len += std::strlen(message_parts[i]);
}
}
message.reserve(total_len);
for (int i = 0; i < num_parts; ++i) {
if (message_parts[i] != nullptr) {
message.append(message_parts[i]);
}
}
Error error(kind, message, backtrace);
last_error_ = details::ObjectUnsafe::ObjectPtrFromObjectRef<ErrorObj>(std::move(error));
}
void MoveFromRaised(TVMFFIObjectHandle* result) {
result[0] = details::ObjectUnsafe::MoveObjectPtrToTVMFFIObjectPtr(std::move(last_error_));
}
static SafeCallContext* ThreadLocal() {
static thread_local SafeCallContext ctx;
return &ctx;
}
private:
ObjectPtr<ErrorObj> last_error_;
};
} // namespace ffi
} // namespace tvm
void TVMFFIErrorSetRaisedFromCStr(const char* kind, const char* message) {
// NOTE: run backtrace here to simplify the depth of tracekback
tvm::ffi::SafeCallContext::ThreadLocal()->SetRaisedByCstr(
kind, message, TVMFFIBacktrace(nullptr, 0, nullptr, 0));
}
void TVMFFIErrorSetRaisedFromCStrParts(const char* kind, const char** message_parts,
int32_t num_parts) {
// NOTE: run backtrace here to simplify the depth of tracekback
tvm::ffi::SafeCallContext::ThreadLocal()->SetRaisedByCstrParts(
kind, message_parts, num_parts, TVMFFIBacktrace(nullptr, 0, nullptr, 0));
}
void TVMFFIErrorSetRaised(TVMFFIObjectHandle error) {
tvm::ffi::SafeCallContext::ThreadLocal()->SetRaised(error);
}
void TVMFFIErrorMoveFromRaised(TVMFFIObjectHandle* result) {
tvm::ffi::SafeCallContext::ThreadLocal()->MoveFromRaised(result);
}
int TVMFFIErrorCreate(const TVMFFIByteArray* kind, const TVMFFIByteArray* message,
const TVMFFIByteArray* backtrace, TVMFFIObjectHandle* out) {
// log other errors to the logger
TVM_FFI_LOG_EXCEPTION_CALL_BEGIN();
try {
tvm::ffi::Error error(std::string(kind->data, kind->size),
std::string(message->data, message->size),
std::string(backtrace->data, backtrace->size));
*out = tvm::ffi::details::ObjectUnsafe::MoveObjectRefToTVMFFIObjectPtr(std::move(error));
return 0;
} catch (const std::bad_alloc& e) {
return -1;
}
TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFIErrorCreate);
}
int TVMFFIErrorCreateWithCauseAndExtraContext(
const TVMFFIByteArray* kind, const TVMFFIByteArray* message, const TVMFFIByteArray* backtrace,
TVMFFIObjectHandle cause_chain, TVMFFIObjectHandle extra_context, TVMFFIObjectHandle* out) {
// log other errors to the logger
TVM_FFI_LOG_EXCEPTION_CALL_BEGIN();
try {
std::optional<tvm::ffi::Error> cause_chain_error;
if (cause_chain != nullptr) {
cause_chain_error = tvm::ffi::details::ObjectUnsafe::ObjectRefFromObjectPtr<tvm::ffi::Error>(
tvm::ffi::details::ObjectUnsafe::ObjectPtrFromUnowned<tvm::ffi::ErrorObj>(
static_cast<tvm::ffi::ErrorObj*>(cause_chain)));
}
std::optional<tvm::ffi::ObjectRef> extra_context_ref;
if (extra_context != nullptr) {
extra_context_ref =
tvm::ffi::details::ObjectUnsafe::ObjectRefFromObjectPtr<tvm::ffi::ObjectRef>(
tvm::ffi::details::ObjectUnsafe::ObjectPtrFromUnowned<tvm::ffi::Object>(
static_cast<tvm::ffi::Object*>(extra_context)));
}
tvm::ffi::Error error(std::string(kind->data, kind->size),
std::string(message->data, message->size),
std::string(backtrace->data, backtrace->size),
std::move(cause_chain_error), std::move(extra_context_ref));
*out = tvm::ffi::details::ObjectUnsafe::MoveObjectRefToTVMFFIObjectPtr(std::move(error));
return 0;
} catch (const std::bad_alloc& e) {
return -1;
}
TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFIErrorCreateWithCauseAndExtraContext);
}