WIP: support_string_class_attr #415

Closed
abdul124 wants to merge 2 commits from support_string_class_attr into master
4 changed files with 75 additions and 7 deletions

View File

@ -0,0 +1,20 @@
from min_artiq import *
@nac3
class Foo:
attr: Kernel[str]
@kernel
def __init__(self):
self.attr = "attr"
@nac3
class Bar:
core: KernelInvariant[Core]
def __init__(self):
self.core = Core()
@kernel
def run(self):
a = Foo()
if __name__ == "__main__":
Bar().run()

View File

@ -0,0 +1,24 @@
from min_artiq import *
from numpy import int32
@nac3
class Demo:
core: KernelInvariant[Core]
attr1: KernelInvariant[str]
attr2: KernelInvariant[int32]
def __init__(self):
self.core = Core()
self.attr2 = 32
self.attr1 = "SAMPLE"
@kernel
def run(self):
print_int32(self.attr2)
self.attr1
if __name__ == "__main__":
Demo().run()

View File

@ -102,6 +102,7 @@ pub struct PrimitivePythonId {
float: u64,
float64: u64,
bool: u64,
string: u64,
list: u64,
ndarray: u64,
tuple: u64,
@ -921,6 +922,7 @@ impl Nac3 {
uint32: get_attr_id(numpy_mod, "uint32"),
uint64: get_attr_id(numpy_mod, "uint64"),
bool: get_attr_id(builtins_mod, "bool"),
string: get_attr_id(builtins_mod, "str"),
float: get_attr_id(builtins_mod, "float"),
float64: get_attr_id(numpy_mod, "float64"),
list: get_attr_id(builtins_mod, "list"),

View File

@ -35,6 +35,7 @@ pub enum PrimitiveValue {
U64(u64),
F64(f64),
Bool(bool),
Str(String),
}
/// An entry in the [`DeferredEvaluationStore`], containing the deferred types, a [`PyObject`]
@ -154,6 +155,7 @@ impl StaticValue for PythonValue {
PrimitiveValue::Bool(val) => {
ctx.ctx.i8_type().const_int(u64::from(*val), false).into()
}
PrimitiveValue::Str(val) => ctx.ctx.const_string(val.as_bytes(), true).into(),
});
}
if let Some(global) = ctx.module.get_global(&self.id.to_string()) {
@ -300,7 +302,14 @@ impl InnerResolver {
let ty_id: u64 = self.helper.id_fn.call1(py, (pyty,))?.extract(py)?;
let ty_ty_id: u64 =
self.helper.id_fn.call1(py, (self.helper.type_fn.call1(py, (pyty,))?,))?.extract(py)?;
let py_obj_id: u64 = self.helper.id_fn.call1(py, (pyty,))?.extract(py)?;
let get_def_id = || {
Review

This is only used once. Worth defining?

This is only used once. Worth defining?
Review

Added this at the top for clarity in if condition, but yes since it is used only once, will rewrite this and move it with the calling condition.

Added this at the top for clarity in if condition, but yes since it is used only once, will rewrite this and move it with the calling condition.
self.pyid_to_def
.read()
.get(&ty_id)
.copied()
.or_else(|| self.pyid_to_def.read().get(&py_obj_id).copied())
};
if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 {
Ok(Ok((primitives.int32, true)))
} else if ty_id == self.primitive_ids.int64 {
@ -311,6 +320,8 @@ impl InnerResolver {
Ok(Ok((primitives.uint64, true)))
} else if ty_id == self.primitive_ids.bool {
Ok(Ok((primitives.bool, true)))
} else if ty_id == self.primitive_ids.string {
Ok(Ok((primitives.str, true)))
} else if ty_id == self.primitive_ids.float || ty_id == self.primitive_ids.float64 {
Ok(Ok((primitives.float, true)))
} else if ty_id == self.primitive_ids.exception {
@ -333,7 +344,7 @@ impl InnerResolver {
Ok(Ok((primitives.option, false)))
} else if ty_id == self.primitive_ids.none {
unreachable!("none cannot be typeid")
} else if let Some(def_id) = self.pyid_to_def.read().get(&ty_id).copied() {
} else if let Some(def_id) = get_def_id() {
let def = defs[def_id.0].read();
let TopLevelDef::Class { object_id, type_vars, fields, methods, .. } = &*def else {
// only object is supported, functions are not supported
@ -599,12 +610,15 @@ impl InnerResolver {
let pyid_to_def = self.pyid_to_def.read();
let constructor_ty = pyid_to_def.get(&py_obj_id).and_then(|def_id| {
defs.iter().find_map(|def| {
if let TopLevelDef::Class { object_id, methods, constructor, .. } = &*def.read() {
if object_id == def_id
&& constructor.is_some()
&& methods.iter().any(|(s, _, _)| s == &"__init__".into())
if let Some(rear_guard) = def.try_read() {
Review

rear_guard ?

rear_guard ?
Review

The previous code entered deadlock since the last element inside the def was locked (not sure about the reason for this), so to avoid that, I replaced the read() function with try_read to prevent the blocking behavior.

The previous code entered deadlock since the last element inside the def was locked (not sure about the reason for this), so to avoid that, I replaced the _read()_ function with _try_read_ to prevent the blocking behavior.
Review

Sounds like the code would then fail randomly instead of deadlocking, then?

Sounds like the code would then fail randomly instead of deadlocking, then?
Review

From what I have tested, only the last element inside the class definitions was locked. I was unable to see what it corresponded to in the class, but methods including the constructor were already processed. I think avoiding deadlock here should be more important as the code after it can give more meaningful error messages. I will further look into the reason for this blocking and update here.

From what I have tested, only the last element inside the class definitions was locked. I was unable to see what it corresponded to in the class, but methods including the constructor were already processed. I think avoiding deadlock here should be more important as the code after it can give more meaningful error messages. I will further look into the reason for this blocking and update here.
Review

Please break it into another PR while you investigate it.

Please break it into another PR while you investigate it.
if let TopLevelDef::Class { object_id, methods, constructor, .. } = &*rear_guard
{
return *constructor;
if object_id == def_id
&& constructor.is_some()
&& methods.iter().any(|(s, _, _)| s == &"__init__".into())
{
return *constructor;
}
}
}
None
@ -625,6 +639,7 @@ impl InnerResolver {
self.primitive_ids.generic_alias.1,
]
.contains(&self.helper.id_fn.call1(py, (ty.clone(),))?.extract::<u64>(py)?)
|| self.pyid_to_def.read().contains_key(&py_obj_id)
{
obj
} else {
@ -881,6 +896,10 @@ impl InnerResolver {
let val: f64 = obj.extract().unwrap();
self.id_to_primitive.write().insert(id, PrimitiveValue::F64(val));
Ok(Some(ctx.ctx.f64_type().const_float(val).into()))
} else if ty_id == self.primitive_ids.string {
let val: String = obj.extract().unwrap();
self.id_to_primitive.write().insert(id, PrimitiveValue::Str(val.clone()));
Ok(Some(ctx.ctx.const_string(val.as_bytes(), true).into()))
} else if ty_id == self.primitive_ids.list {
let id_str = id.to_string();
@ -1123,6 +1142,9 @@ impl InnerResolver {
} else if ty_id == self.primitive_ids.bool {
let val: bool = obj.extract()?;
Ok(SymbolValue::Bool(val))
} else if ty_id == self.primitive_ids.string {
let val: String = obj.extract()?;
Ok(SymbolValue::Str(val))
} else if ty_id == self.primitive_ids.float || ty_id == self.primitive_ids.float64 {
let val: f64 = obj.extract()?;
Ok(SymbolValue::Double(val))