Skip to content

Commit

Permalink
feat: support backtrace in runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
NeverRaR committed Apr 24, 2023
1 parent 1aaee4a commit cc5416b
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 38 deletions.
15 changes: 10 additions & 5 deletions kclvm/compiler/src/codegen/llvm/context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2021 The KCL Authors. All rights reserved.

use core::panic;
use indexmap::{IndexMap, IndexSet};
use inkwell::basic_block::BasicBlock;
use inkwell::builder::Builder;
Expand Down Expand Up @@ -418,28 +419,31 @@ impl<'ctx> ValueMethods for LLVMCodeGenContext<'ctx> {
}
/// Construct a function value using a native function.
fn function_value(&self, function: FunctionValue<'ctx>) -> Self::Value {
let func_name = function.get_name().to_str().unwrap();
let func_name_ptr = self.native_global_string(func_name, func_name).into();
let lambda_fn_ptr = self.builder.build_bitcast(
function.as_global_value().as_pointer_value(),
self.context.i64_type().ptr_type(AddressSpace::default()),
"",
);
self.build_call(
&ApiFunc::kclvm_value_Function_using_ptr.name(),
&[lambda_fn_ptr],
&[lambda_fn_ptr, func_name_ptr],
)
}
/// Construct a closure function value with the closure variable.
fn closure_value(&self, function: FunctionValue<'ctx>, closure: Self::Value) -> Self::Value {
let func_name = function.get_name().to_str().unwrap();
let func_name_ptr = self.native_global_string(func_name, func_name).into();
// Convert the function to a i64 pointer to store it into the function value.
let fn_ptr = self.builder.build_bitcast(
function.as_global_value().as_pointer_value(),
self.context.i64_type().ptr_type(AddressSpace::default()),
"",
);
let name = self.native_global_string("", "").into();
self.build_call(
&ApiFunc::kclvm_value_Function.name(),
&[fn_ptr, closure, name],
&[fn_ptr, closure, func_name_ptr],
)
}
/// Construct a schema function value using native functions.
Expand Down Expand Up @@ -1674,11 +1678,12 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
self.context.i64_type().ptr_type(AddressSpace::default()),
"",
);
let name = self.native_global_string("", "").into();
let func_name = function.get_name().to_str().unwrap();
let func_name_ptr = self.native_global_string(func_name, func_name).into();
let none_value = self.none_value();
self.build_call(
&ApiFunc::kclvm_value_Function.name(),
&[lambda_fn_ptr, none_value, name],
&[lambda_fn_ptr, none_value, func_name_ptr],
)
};
Ok(value)
Expand Down
5 changes: 3 additions & 2 deletions kclvm/error/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,14 @@ impl From<Loc> for Position {

impl Diagnostic {
pub fn new(level: Level, message: &str, pos: Position) -> Self {
Diagnostic::new_with_code(level, message, pos, None)
Diagnostic::new_with_code(level, message, None, pos, None)
}

/// New a diagnostic with error code.
pub fn new_with_code(
level: Level,
message: &str,
note: Option<&str>,
pos: Position,
code: Option<DiagnosticId>,
) -> Self {
Expand All @@ -112,7 +113,7 @@ impl Diagnostic {
pos,
style: Style::LineAndColumn,
message: message.to_string(),
note: None,
note: note.map(|s| s.to_string()),
}],
code,
}
Expand Down
60 changes: 46 additions & 14 deletions kclvm/error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ impl Handler {
let diag = Diagnostic::new_with_code(
Level::Error,
&message,
None,
pos,
Some(DiagnosticId::Error(E1001.kind)),
);
Expand All @@ -109,6 +110,7 @@ impl Handler {
let diag = Diagnostic::new_with_code(
Level::Error,
msg,
None,
pos,
Some(DiagnosticId::Error(E2G22.kind)),
);
Expand All @@ -122,6 +124,7 @@ impl Handler {
let diag = Diagnostic::new_with_code(
Level::Error,
msg,
None,
pos,
Some(DiagnosticId::Error(E2L23.kind)),
);
Expand Down Expand Up @@ -219,26 +222,54 @@ impl Handler {

impl From<PanicInfo> for Diagnostic {
fn from(panic_info: PanicInfo) -> Self {
let mut diag = Diagnostic::new_with_code(
Level::Error,
if panic_info.kcl_arg_msg.is_empty() {
&panic_info.message
} else {
&panic_info.kcl_arg_msg
},
Position {
filename: panic_info.kcl_file.clone(),
line: panic_info.kcl_line as u64,
column: None,
},
Some(DiagnosticId::Error(E3M38.kind)),
);
let panic_msg = if panic_info.kcl_arg_msg.is_empty() {
&panic_info.message
} else {
&panic_info.kcl_arg_msg
};

let mut diag = if panic_info.backtrace.is_empty() {
Diagnostic::new_with_code(
Level::Error,
&panic_msg,
None,
Position {
filename: panic_info.kcl_file.clone(),
line: panic_info.kcl_line as u64,
column: None,
},
Some(DiagnosticId::Error(E3M38.kind)),
)
} else {
let mut backtrace_msg = "backtrace:\n".to_string();
let mut backtrace = panic_info.backtrace.clone();
backtrace.reverse();
for (index, frame) in backtrace.iter().enumerate() {
backtrace_msg = format!(
"{backtrace_msg}\t{index}: {}\n\t\tat {}:{}:{}\n",
frame.func, frame.file, frame.line, frame.col
);
}
Diagnostic::new_with_code(
Level::Error,
&panic_msg,
Some(&backtrace_msg),
Position {
filename: panic_info.kcl_file.clone(),
line: panic_info.kcl_line as u64,
column: None,
},
Some(DiagnosticId::Error(E3M38.kind)),
)
};

if panic_info.kcl_config_meta_file.is_empty() {
return diag;
}
let mut config_meta_diag = Diagnostic::new_with_code(
Level::Error,
&panic_info.kcl_config_meta_arg_msg,
None,
Position {
filename: panic_info.kcl_config_meta_file.clone(),
line: panic_info.kcl_config_meta_line as u64,
Expand Down Expand Up @@ -297,6 +328,7 @@ impl ParseError {
Ok(Diagnostic::new_with_code(
Level::Error,
&self.to_string(),
None,
loc.into(),
Some(DiagnosticId::Error(ErrorKind::InvalidSyntax)),
))
Expand Down
Binary file modified kclvm/runtime/src/_kclvm.bc
Binary file not shown.
2 changes: 1 addition & 1 deletion kclvm/runtime/src/_kclvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ kclvm_float_t* kclvm_value_Float_ptr(kclvm_value_ref_t* p);

kclvm_value_ref_t* kclvm_value_Function(uint64_t* fn_ptr, kclvm_value_ref_t* closure, kclvm_char_t* external_name);

kclvm_value_ref_t* kclvm_value_Function_using_ptr(uint64_t* fn_ptr);
kclvm_value_ref_t* kclvm_value_Function_using_ptr(uint64_t* fn_ptr, kclvm_char_t* external_name);

kclvm_value_ref_t* kclvm_value_Int(kclvm_int_t v);

Expand Down
2 changes: 1 addition & 1 deletion kclvm/runtime/src/_kclvm.ll
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ declare %kclvm_float_t* @kclvm_value_Float_ptr(%kclvm_value_ref_t* %p);

declare %kclvm_value_ref_t* @kclvm_value_Function(i64* %fn_ptr, %kclvm_value_ref_t* %closure, %kclvm_char_t* %external_name);

declare %kclvm_value_ref_t* @kclvm_value_Function_using_ptr(i64* %fn_ptr);
declare %kclvm_value_ref_t* @kclvm_value_Function_using_ptr(i64* %fn_ptr, %kclvm_char_t* %external_name);

declare %kclvm_value_ref_t* @kclvm_value_Int(%kclvm_int_t %v);

Expand Down
6 changes: 3 additions & 3 deletions kclvm/runtime/src/_kclvm_api_spec.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022 The KCL Authors. All rights reserved.
// Copyright 2023 The KCL Authors. All rights reserved.

// Auto generated by <make gen-api-spec> command, DONOT EDIT!!!

Expand Down Expand Up @@ -275,8 +275,8 @@
// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Function(i64* %fn_ptr, %kclvm_value_ref_t* %closure, %kclvm_char_t* %external_name);

// api-spec: kclvm_value_Function_using_ptr
// api-spec(c): kclvm_value_ref_t* kclvm_value_Function_using_ptr(uint64_t* fn_ptr);
// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Function_using_ptr(i64* %fn_ptr);
// api-spec(c): kclvm_value_ref_t* kclvm_value_Function_using_ptr(uint64_t* fn_ptr, kclvm_char_t* external_name);
// api-spec(llvm): declare %kclvm_value_ref_t* @kclvm_value_Function_using_ptr(i64* %fn_ptr, %kclvm_char_t* %external_name);

// api-spec: kclvm_value_schema_function
// api-spec(c): kclvm_value_ref_t* kclvm_value_schema_function(uint64_t* fn_ptr, uint64_t* check_fn_ptr, kclvm_char_t* tpe);
Expand Down
36 changes: 36 additions & 0 deletions kclvm/runtime/src/api/kclvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,13 +293,15 @@ pub struct OptionHelp {
#[derive(PartialEq, Eq, Clone, Default, Debug, Serialize, Deserialize)]
pub struct PanicInfo {
pub __kcl_PanicInfo__: bool, // "__kcl_PanicInfo__"
pub backtrace: Vec<BacktraceFrame>,

pub rust_file: String,
pub rust_line: i32,
pub rust_col: i32,

pub kcl_pkgpath: String,
pub kcl_file: String,
pub kcl_func: String,
pub kcl_line: i32,
pub kcl_col: i32,
pub kcl_arg_msg: String,
Expand Down Expand Up @@ -368,6 +370,7 @@ pub struct Context {

pub main_pkg_path: String,
pub main_pkg_files: Vec<String>,
pub backtrace: Vec<BacktraceFrame>,

pub imported_pkgpath: HashSet<String>,
pub app_args: HashMap<String, u64>,
Expand All @@ -385,10 +388,43 @@ pub struct Context {
pub objects: IndexSet<usize>,
}

#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
pub struct BacktraceFrame {
pub file: String,
pub func: String,
pub col: i32,
pub line: i32,
}
impl Default for BacktraceFrame {
fn default() -> Self {
Self {
file: Default::default(),
func: "_kclvm_main".to_string(),
col: Default::default(),
line: Default::default(),
}
}
}

impl BacktraceFrame {
pub fn from_panic_info(info: &PanicInfo) -> Self {
Self {
file: info.kcl_file.clone(),
func: info.kcl_func.clone(),
col: info.kcl_col,
line: info.kcl_line,
}
}
}

impl Context {
pub fn new() -> Self {
Context {
instances: RefCell::new(HashMap::new()),
panic_info: PanicInfo {
kcl_func: "kclvm_main".to_string(),
..Default::default()
},
..Default::default()
}
}
Expand Down
22 changes: 15 additions & 7 deletions kclvm/runtime/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub mod api;
pub use api::*;
use std::fmt;

use crate::PanicInfo;
use crate::{BacktraceFrame, PanicInfo};

#[allow(non_camel_case_types)]
type kclvm_value_ref_t = crate::ValueRef;
Expand Down Expand Up @@ -189,16 +189,24 @@ impl crate::Context {
pub fn set_panic_info(&mut self, info: &std::panic::PanicInfo) {
self.panic_info.__kcl_PanicInfo__ = true;

if let Some(s) = info.payload().downcast_ref::<&str>() {
self.panic_info.message = s.to_string();
self.panic_info.message = if let Some(s) = info.payload().downcast_ref::<&str>() {
s.to_string()
} else if let Some(s) = info.payload().downcast_ref::<&String>() {
self.panic_info.message = (*s).clone();
(*s).clone()
} else if let Some(s) = info.payload().downcast_ref::<String>() {
self.panic_info.message = (*s).clone();
(*s).clone()
} else {
self.panic_info.message = "".to_string();
"".to_string()
};
if self.cfg.debug_mode {
self.panic_info.backtrace = self.backtrace.clone();
self.panic_info.backtrace.push(BacktraceFrame {
file: self.panic_info.kcl_file.clone(),
func: self.panic_info.kcl_func.clone(),
col: self.panic_info.kcl_col,
line: self.panic_info.kcl_line,
});
}

if let Some(location) = info.location() {
self.panic_info.rust_file = location.file().to_string();
self.panic_info.rust_line = location.line() as i32;
Expand Down
29 changes: 24 additions & 5 deletions kclvm/runtime/src/value/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,10 @@ pub unsafe extern "C" fn kclvm_value_Function(
#[runtime_fn]
pub unsafe extern "C" fn kclvm_value_Function_using_ptr(
fn_ptr: *const u64,
external_name: *const kclvm_char_t,
) -> *mut kclvm_value_ref_t {
new_mut_ptr(ValueRef::func(fn_ptr as u64, 0, ValueRef::none(), "", ""))
let name = c2str(external_name);
new_mut_ptr(ValueRef::func(fn_ptr as u64, 0, ValueRef::none(), name, ""))
}

#[no_mangle]
Expand Down Expand Up @@ -615,8 +617,13 @@ pub unsafe extern "C" fn kclvm_value_function_invoke(
let fn_ptr = func.fn_ptr;
let closure = &func.closure;
let is_schema = !func.runtime_type.is_empty();
let is_external = !func.external_name.is_empty();
let ctx_ref = mut_ptr_as_ref(ctx);
if ctx_ref.cfg.debug_mode {
ctx_ref
.backtrace
.push(BacktraceFrame::from_panic_info(&ctx_ref.panic_info));
ctx_ref.panic_info.kcl_func = func.external_name.clone();
}
let now_meta_info = ctx_ref.panic_info.clone();
unsafe {
let call_fn: SchemaTypeFunc = transmute_copy(&fn_ptr);
Expand Down Expand Up @@ -652,9 +659,6 @@ pub unsafe extern "C" fn kclvm_value_function_invoke(
args_new.list_append_unpack(&closure_new);
call_fn(ctx, args_new.into_raw(), kwargs)
// Normal kcl function, call directly
} else if is_external {
let name = format!("{}\0", func.external_name);
kclvm_plugin_invoke(name.as_ptr() as *const i8, args, kwargs)
} else {
args_ref.list_append_unpack_first(closure);
let args = args_ref.clone().into_raw();
Expand All @@ -665,6 +669,9 @@ pub unsafe extern "C" fn kclvm_value_function_invoke(
let schema_value = ptr_as_ref(value);
schema_value.schema_check_attr_optional(true);
}
if ctx_ref.cfg.debug_mode {
ctx_ref.backtrace.pop();
}
ctx_ref.panic_info = now_meta_info;
return value;
};
Expand Down Expand Up @@ -2263,6 +2270,14 @@ pub unsafe extern "C" fn kclvm_schema_value_new(
if schema_value_or_func.is_func() {
let schema_func = schema_value_or_func.as_function();
let schema_fn_ptr = schema_func.fn_ptr;
let ctx_ref = mut_ptr_as_ref(ctx);
let now_meta_info = ctx_ref.panic_info.clone();
if ctx_ref.cfg.debug_mode {
ctx_ref
.backtrace
.push(BacktraceFrame::from_panic_info(&ctx_ref.panic_info));
ctx_ref.panic_info.kcl_func = schema_func.runtime_type.clone();
}
let value = unsafe {
let org_args = ptr_as_ref(args).deep_copy();
let schema_fn: SchemaTypeFunc = transmute_copy(&schema_fn_ptr);
Expand Down Expand Up @@ -2324,6 +2339,10 @@ pub unsafe extern "C" fn kclvm_schema_value_new(
}
schema_fn(ctx, args, kwargs)
};
ctx_ref.panic_info = now_meta_info;
if ctx_ref.cfg.debug_mode {
ctx_ref.backtrace.pop();
}
value
} else {
let config = ptr_as_ref(config);
Expand Down

0 comments on commit cc5416b

Please sign in to comment.