compiler, firmware: use Pascal strings everywhere.

This removes a large amount of very ugly code, and also simplifies
the compiler and runtime.
This commit is contained in:
whitequark 2017-02-03 11:46:45 +00:00
parent e13d8919ff
commit fd8b11532f
17 changed files with 188 additions and 252 deletions

View File

@ -36,13 +36,6 @@ class TKeyword(types.TMono):
def is_keyword(typ):
return isinstance(typ, TKeyword)
class TExceptionTypeInfo(types.TMono):
def __init__(self):
super().__init__("exntypeinfo")
def is_exn_typeinfo(typ):
return isinstance(typ, TExceptionTypeInfo)
class Value:
"""
An SSA value that keeps track of its uses.

View File

@ -1332,10 +1332,6 @@ class ARTIQIRGenerator(algorithm.Visitor):
rhs_length = self.iterable_len(rhs)
result_length = self.append(ir.Arith(ast.Add(loc=None), lhs_length, rhs_length))
if builtins.is_str(node.left.type):
result_last = result_length
result_length = self.append(ir.Arith(ast.Add(loc=None), result_length,
ir.Constant(1, self._size_type)))
result = self.append(ir.Alloc([result_length], node.type))
# Copy lhs
@ -1359,10 +1355,6 @@ class ARTIQIRGenerator(algorithm.Visitor):
lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, rhs_length)),
body_gen)
if builtins.is_str(node.left.type):
self.append(ir.SetElem(result, result_last,
ir.Constant(0, builtins.TInt(types.TValue(8)))))
return result
else:
assert False
@ -1564,13 +1556,13 @@ class ARTIQIRGenerator(algorithm.Visitor):
# Keep this function with builtins.TException.attributes.
def alloc_exn(self, typ, message=None, param0=None, param1=None, param2=None):
typ = typ.find()
name = "{}:{}".format(typ.id, typ.name)
attributes = [
ir.Constant("{}:{}".format(typ.id, typ.name),
ir.TExceptionTypeInfo()), # typeinfo
ir.Constant("<not thrown>", builtins.TStr()), # file
ir.Constant(0, builtins.TInt32()), # line
ir.Constant(0, builtins.TInt32()), # column
ir.Constant("<not thrown>", builtins.TStr()), # function
ir.Constant(name, builtins.TStr()), # typeinfo
ir.Constant("<not thrown>", builtins.TStr()), # file
ir.Constant(0, builtins.TInt32()), # line
ir.Constant(0, builtins.TInt32()), # column
ir.Constant("<not thrown>", builtins.TStr()), # function
]
if message is None:
@ -1892,7 +1884,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
else:
explanation = node.loc.source()
self.append(ir.Builtin("printf", [
ir.Constant("assertion failed at %s: %s\n", builtins.TStr()),
ir.Constant("assertion failed at %.*s: %.*s\n\x00", builtins.TStr()),
ir.Constant(str(node.loc.begin()), builtins.TStr()),
ir.Constant(str(explanation), builtins.TStr()),
], builtins.TNone()))
@ -1905,7 +1897,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
subexpr_body = self.current_block = self.add_block("assert.subexpr.body")
self.append(ir.Builtin("printf", [
ir.Constant(" (%s) = ", builtins.TStr()),
ir.Constant(" (%.*s) = \x00", builtins.TStr()),
ir.Constant(subexpr_node.loc.source(), builtins.TStr())
], builtins.TNone()))
subexpr_value = self.append(ir.Builtin("unwrap", [subexpr_value_opt],
@ -1937,7 +1929,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
def flush():
nonlocal format_string, args
if format_string != "":
printf(format_string, *args)
printf(format_string + "\x00", *args)
format_string = ""
args = []
@ -1961,7 +1953,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
elif builtins.is_none(value.type):
format_string += "None"
elif builtins.is_bool(value.type):
format_string += "%s"
format_string += "%.*s"
args.append(self.append(ir.Select(value,
ir.Constant("True", builtins.TStr()),
ir.Constant("False", builtins.TStr()))))
@ -1979,9 +1971,9 @@ class ARTIQIRGenerator(algorithm.Visitor):
args.append(value)
elif builtins.is_str(value.type):
if as_repr:
format_string += "\"%s\""
format_string += "\"%.*s\""
else:
format_string += "%s"
format_string += "%.*s"
args.append(value)
elif builtins.is_listish(value.type):
if builtins.is_list(value.type):
@ -2000,7 +1992,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
head = self.current_block
if_last = self.current_block = self.add_block("print.comma")
printf(", ")
printf(", \x00")
tail = self.current_block = self.add_block("print.tail")
if_last.append(ir.Branch(tail))
@ -2032,7 +2024,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
param2 = self.append(ir.GetAttr(value, "__param1__"))
param3 = self.append(ir.GetAttr(value, "__param2__"))
format_string += "%s(%s, %lld, %lld, %lld)"
format_string += "%.*s(%.*s, %lld, %lld, %lld)"
args += [name, message, param1, param2, param3]
else:
assert False

View File

@ -20,6 +20,8 @@ lli64 = ll.IntType(64)
lldouble = ll.DoubleType()
llptr = ll.IntType(8).as_pointer()
llptrptr = ll.IntType(8).as_pointer().as_pointer()
llslice = ll.LiteralStructType([llptr, lli32])
llsliceptr = ll.LiteralStructType([llptr, lli32]).as_pointer()
llmetadata = ll.MetaData()
@ -216,8 +218,6 @@ class LLVMIRGenerator:
return ll.IntType(builtins.get_int_width(typ))
elif builtins.is_float(typ):
return lldouble
elif builtins.is_str(typ) or ir.is_exn_typeinfo(typ):
return llptr
elif builtins.is_listish(typ):
lleltty = self.llty_of_type(builtins.get_iterable_elt(typ))
return ll.LiteralStructType([lleltty.as_pointer(), lli32])
@ -229,7 +229,7 @@ class LLVMIRGenerator:
elif ir.is_option(typ):
return ll.LiteralStructType([lli1, self.llty_of_type(typ.params["value"])])
elif ir.is_keyword(typ):
return ll.LiteralStructType([llptr, self.llty_of_type(typ.params["value"])])
return ll.LiteralStructType([llslice, self.llty_of_type(typ.params["value"])])
elif ir.is_environment(typ):
llty = self.llcontext.get_identified_type("env.{}".format(typ.env_name))
if llty.elements is None:
@ -262,8 +262,7 @@ class LLVMIRGenerator:
def llstr_of_str(self, value, name=None, linkage="private", unnamed_addr=True):
if isinstance(value, str):
assert "\0" not in value
as_bytes = (value + "\0").encode("utf-8")
as_bytes = value.encode("utf-8")
else:
as_bytes = value
@ -295,19 +294,14 @@ class LLVMIRGenerator:
elif isinstance(const.value, (int, float)):
return ll.Constant(llty, const.value)
elif isinstance(const.value, (str, bytes)):
if ir.is_exn_typeinfo(const.type):
# Exception typeinfo; should be merged with identical others
name = "__artiq_exn_" + const.value
linkage = "linkonce"
unnamed_addr = False
if isinstance(const.value, str):
value = const.value.encode('utf-8')
else:
# Just a string
name = None
linkage = "private"
unnamed_addr = True
value = const.value
return self.llstr_of_str(const.value, name=name,
linkage=linkage, unnamed_addr=unnamed_addr)
llptr = self.llstr_of_str(const.value, linkage="private", unnamed_addr=True)
lllen = ll.Constant(lli32, len(const.value))
return ll.Constant(llty, (llptr, lllen))
else:
assert False
@ -318,8 +312,6 @@ class LLVMIRGenerator:
if name in "llvm.donothing":
llty = ll.FunctionType(llvoid, [])
elif name in "llvm.trap":
llty = ll.FunctionType(llvoid, [])
elif name == "llvm.floor.f64":
llty = ll.FunctionType(lldouble, [lldouble])
elif name == "llvm.round.f64":
@ -344,14 +336,14 @@ class LLVMIRGenerator:
llty = ll.FunctionType(llvoid, [self.llty_of_type(builtins.TException())])
elif name == "__artiq_reraise":
llty = ll.FunctionType(llvoid, [])
elif name == "strlen":
llty = ll.FunctionType(lli32, [llptr])
elif name == "strcmp":
llty = ll.FunctionType(lli32, [llptr, llptr])
elif name in "abort":
llty = ll.FunctionType(llvoid, [])
elif name == "memcmp":
llty = ll.FunctionType(lli32, [llptr, llptr, lli32])
elif name == "send_rpc":
llty = ll.FunctionType(llvoid, [lli32, llptr, llptrptr])
llty = ll.FunctionType(llvoid, [lli32, llsliceptr, llptrptr])
elif name == "send_async_rpc":
llty = ll.FunctionType(llvoid, [lli32, llptr, llptrptr])
llty = ll.FunctionType(llvoid, [lli32, llsliceptr, llptrptr])
elif name == "recv_rpc":
llty = ll.FunctionType(lli32, [llptr])
elif name == "now":
@ -423,7 +415,7 @@ class LLVMIRGenerator:
llobjects[obj_typ].append(llobject.bitcast(llptr))
llrpcattrty = self.llcontext.get_identified_type("A")
llrpcattrty.elements = [lli32, llptr, llptr]
llrpcattrty.elements = [lli32, llslice, llslice]
lldescty = self.llcontext.get_identified_type("D")
lldescty.elements = [llrpcattrty.as_pointer().as_pointer(), llptr.as_pointer()]
@ -445,15 +437,14 @@ class LLVMIRGenerator:
if not (types.is_function(typ) or types.is_method(typ) or types.is_rpc(typ) or
name == "__objectid__"):
rpctag = b"Os" + self._rpc_tag(typ, error_handler=rpc_tag_error) + b":n\x00"
llrpctag = self.llstr_of_str(rpctag)
rpctag = b"Os" + self._rpc_tag(typ, error_handler=rpc_tag_error) + b":n"
else:
llrpctag = ll.Constant(llptr, None)
rpctag = b""
llrpcattrinit = ll.Constant(llrpcattrty, [
ll.Constant(lli32, offset),
llrpctag,
self.llstr_of_str(name)
self.llconst_of_const(ir.Constant(rpctag, builtins.TStr())),
self.llconst_of_const(ir.Constant(name, builtins.TStr()))
])
if name == "__objectid__":
@ -615,10 +606,6 @@ class LLVMIRGenerator:
name=insn.name)
else:
assert False
elif builtins.is_str(insn.type):
llsize = self.map(insn.operands[0])
llvalue = self.llbuilder.alloca(lli8, size=llsize)
return llvalue
elif builtins.is_listish(insn.type):
llsize = self.map(insn.operands[0])
lleltty = self.llty_of_type(builtins.get_iterable_elt(insn.type))
@ -829,13 +816,9 @@ class LLVMIRGenerator:
def process_GetElem(self, insn):
lst, idx = insn.list(), insn.index()
lllst, llidx = map(self.map, (lst, idx))
if builtins.is_str(lst.type):
llelt = self.llbuilder.gep(lllst, [llidx], inbounds=True)
llvalue = self.llbuilder.load(llelt)
else:
llelts = self.llbuilder.extract_value(lllst, 0)
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
llvalue = self.llbuilder.load(llelt)
llelts = self.llbuilder.extract_value(lllst, 0)
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
llvalue = self.llbuilder.load(llelt)
if isinstance(llvalue.type, ll.PointerType):
self.mark_dereferenceable(llvalue)
return llvalue
@ -843,11 +826,8 @@ class LLVMIRGenerator:
def process_SetElem(self, insn):
lst, idx = insn.list(), insn.index()
lllst, llidx = map(self.map, (lst, idx))
if builtins.is_str(lst.type):
llelt = self.llbuilder.gep(lllst, [llidx], inbounds=True)
else:
llelts = self.llbuilder.extract_value(lllst, 0)
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
llelts = self.llbuilder.extract_value(lllst, 0)
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
return self.llbuilder.store(self.map(insn.value()), llelt)
def process_Coerce(self, insn):
@ -1029,7 +1009,7 @@ class LLVMIRGenerator:
if insn.op == "nop":
return self.llbuilder.call(self.llbuiltin("llvm.donothing"), [])
if insn.op == "abort":
return self.llbuilder.call(self.llbuiltin("llvm.trap"), [])
return self.llbuilder.call(self.llbuiltin("abort"), [])
elif insn.op == "is_some":
lloptarg = self.map(insn.operands[0])
return self.llbuilder.extract_value(lloptarg, 0,
@ -1066,15 +1046,21 @@ class LLVMIRGenerator:
return get_outer(self.map(env), env.type)
elif insn.op == "len":
collection, = insn.operands
if builtins.is_str(collection.type):
return self.llbuilder.call(self.llbuiltin("strlen"), [self.map(collection)])
else:
return self.llbuilder.extract_value(self.map(collection), 1)
return self.llbuilder.extract_value(self.map(collection), 1)
elif insn.op in ("printf", "rtio_log"):
# We only get integers, floats, pointers and strings here.
llargs = map(self.map, insn.operands)
lloperands = []
for i, operand in enumerate(insn.operands):
lloperand = self.map(operand)
if i == 0 and insn.op == "printf" or i == 1 and insn.op == "rtio_log":
lloperands.append(self.llbuilder.extract_value(lloperand, 0))
elif builtins.is_str(operand.type):
lloperands.append(self.llbuilder.extract_value(lloperand, 1))
lloperands.append(self.llbuilder.extract_value(lloperand, 0))
else:
lloperands.append(lloperand)
func_name = self.target.print_function if insn.op == "printf" else insn.op
return self.llbuilder.call(self.llbuiltin(func_name), llargs,
return self.llbuilder.call(self.llbuiltin(func_name), lloperands,
name=insn.name)
elif insn.op == "exncast":
# This is an identity cast at LLVM IR level.
@ -1231,9 +1217,10 @@ class LLVMIRGenerator:
fun_loc)
self.engine.process(diag)
tag += self._rpc_tag(fun_type.ret, ret_error_handler)
tag += b"\x00"
lltag = self.llstr_of_str(tag)
lltag = self.llconst_of_const(ir.Constant(tag, builtins.TStr()))
lltagptr = self.llbuilder.alloca(lltag.type)
self.llbuilder.store(lltag, lltagptr)
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [],
name="rpc.stack")
@ -1256,10 +1243,10 @@ class LLVMIRGenerator:
if fun_type.async:
self.llbuilder.call(self.llbuiltin("send_async_rpc"),
[llservice, lltag, llargs])
[llservice, lltagptr, llargs])
else:
self.llbuilder.call(self.llbuiltin("send_rpc"),
[llservice, lltag, llargs])
[llservice, lltagptr, llargs])
# Don't waste stack space on saved arguments.
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
@ -1446,19 +1433,16 @@ class LLVMIRGenerator:
elif builtins.is_float(typ):
assert isinstance(value, float)
return ll.Constant(llty, value)
elif builtins.is_str(typ):
assert isinstance(value, (str, bytes))
return self.llstr_of_str(value)
elif builtins.is_listish(typ):
assert isinstance(value, (list, numpy.ndarray))
assert isinstance(value, (str, bytes, list, numpy.ndarray))
elt_type = builtins.get_iterable_elt(typ)
llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)])
for i in range(len(value))]
lleltsary = ll.Constant(ll.ArrayType(self.llty_of_type(elt_type), len(llelts)),
list(llelts))
llglobal = ll.GlobalVariable(self.llmodule, lleltsary.type,
self.llmodule.scope.deduplicate("quoted.list"))
name = self.llmodule.scope.deduplicate("quoted.{}".format(typ.name))
llglobal = ll.GlobalVariable(self.llmodule, lleltsary.type, name)
llglobal.initializer = lleltsary
llglobal.linkage = "private"
@ -1556,23 +1540,38 @@ class LLVMIRGenerator:
for target, typ in insn.clauses():
if typ is None:
llclauseexnname = ll.Constant(
self.llty_of_type(ir.TExceptionTypeInfo()), None)
llclauseexnnameptr = ll.Constant(
self.llty_of_type(builtins.TStr()).as_pointer(), None)
else:
exnname = "{}:{}".format(typ.id, typ.name)
llclauseexnname = self.llconst_of_const(
ir.Constant("{}:{}".format(typ.id, typ.name),
ir.TExceptionTypeInfo()))
lllandingpad.add_clause(ll.CatchClause(llclauseexnname))
ir.Constant(exnname, builtins.TStr()))
llclauseexnnameptr = self.llmodule.get_global("exn.{}".format(exnname))
if llclauseexnnameptr is None:
llclauseexnnameptr = ll.GlobalVariable(self.llmodule, llclauseexnname.type,
name="exn.{}".format(exnname))
llclauseexnnameptr.global_constant = True
llclauseexnnameptr.initializer = llclauseexnname
llclauseexnnameptr.linkage = "private"
llclauseexnnameptr.unnamed_addr = True
lllandingpad.add_clause(ll.CatchClause(llclauseexnnameptr))
if typ is None:
self.llbuilder.branch(self.map(target))
else:
llexnmatch = self.llbuilder.call(self.llbuiltin("strcmp"),
[llexnname, llclauseexnname])
llmatchingclause = self.llbuilder.icmp_unsigned('==',
llexnmatch, ll.Constant(lli32, 0))
with self.llbuilder.if_then(llmatchingclause):
self.llbuilder.branch(self.map(target))
llexnlen = self.llbuilder.extract_value(llexnname, 1)
llclauseexnlen = self.llbuilder.extract_value(llclauseexnname, 1)
llmatchinglen = self.llbuilder.icmp_unsigned('==', llexnlen, llclauseexnlen)
with self.llbuilder.if_then(llmatchinglen):
llexnptr = self.llbuilder.extract_value(llexnname, 0)
llclauseexnptr = self.llbuilder.extract_value(llclauseexnname, 0)
llcomparedata = self.llbuilder.call(self.llbuiltin("memcmp"),
[llexnptr, llclauseexnptr, llexnlen])
llmatchingdata = self.llbuilder.icmp_unsigned('==', llcomparedata,
ll.Constant(lli32, 0))
with self.llbuilder.if_then(llmatchingdata):
self.llbuilder.branch(self.map(target))
if self.llbuilder.basic_block.terminator is None:
self.llbuilder.branch(self.map(insn.cleanup()))

View File

@ -115,6 +115,7 @@ dependencies = [
"build_artiq 0.0.0",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins)",
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fringe 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"logger_artiq 0.0.0",

View File

@ -1,8 +1,6 @@
use libc::{c_void, c_char, size_t};
macro_rules! api {
($i:ident) => ({
extern { static $i: c_void; }
extern { static $i: u8; }
api!($i = &$i as *const _)
});
($i:ident, $d:item) => ({
@ -68,9 +66,8 @@ static mut API: &'static [(&'static str, *const ())] = &[
api!(__powidf2),
/* libc */
api!(strcmp),
api!(strlen, extern { fn strlen(s: *const c_char) -> size_t; }),
api!(abort = ::abort),
api!(memcmp, extern { fn memcmp(a: *const u8, b: *mut u8, size: usize); }),
/* libm */
api!(sqrt),

View File

@ -30,15 +30,14 @@ extern {
macro_rules! artiq_raise {
($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => ({
let exn = $crate::kernel_proto::Exception {
name: concat!("0:artiq.coredevice.exceptions.", $name, "\0").as_bytes().as_ptr(),
file: concat!(file!(), "\0").as_bytes().as_ptr(),
name: concat!("0:artiq.coredevice.exceptions.", $name),
file: file!(),
line: line!(),
column: column!(),
// https://github.com/rust-lang/rfcs/pull/1719
function: "(Rust function)\0".as_bytes().as_ptr(),
message: concat!($message, "\0").as_bytes().as_ptr(),
param: [$param0, $param1, $param2],
phantom: ::core::marker::PhantomData
function: "(Rust function)",
message: $message,
param: [$param0, $param1, $param2]
};
#[allow(unused_unsafe)]
unsafe { $crate::__artiq_raise(&exn as *const _) }
@ -48,9 +47,8 @@ macro_rules! artiq_raise {
});
}
use core::{mem, ptr, slice, str};
use core::{mem, ptr, str};
use std::io::Cursor;
use libc::{c_char, size_t};
use cslice::{CSlice, CMutSlice, AsCSlice};
use kernel_proto::*;
use dyld::Library;
@ -125,28 +123,22 @@ extern fn abort() -> ! {
loop {}
}
extern fn send_rpc(service: u32, tag: *const u8, data: *const *const ()) {
extern { fn strlen(s: *const c_char) -> size_t; }
let tag = unsafe { slice::from_raw_parts(tag, strlen(tag as *const c_char)) };
extern fn send_rpc(service: u32, tag: CSlice<u8>, data: *const *const ()) {
while !rpc_queue::empty() {}
send(&RpcSend {
async: false,
service: service,
tag: tag,
tag: tag.as_ref(),
data: data
})
}
extern fn send_async_rpc(service: u32, tag: *const u8, data: *const *const ()) {
extern { fn strlen(s: *const c_char) -> size_t; }
let tag = unsafe { slice::from_raw_parts(tag, strlen(tag as *const c_char)) };
extern fn send_async_rpc(service: u32, tag: CSlice<u8>, data: *const *const ()) {
while rpc_queue::full() {}
rpc_queue::enqueue(|mut slice| {
let length = {
let mut writer = Cursor::new(&mut slice[4..]);
rpc_proto::send_args(&mut writer, service, tag, data)?;
rpc_proto::send_args(&mut writer, service, tag.as_ref(), data)?;
writer.position()
};
proto::write_u32(&mut slice, length as u32)
@ -157,7 +149,7 @@ extern fn send_async_rpc(service: u32, tag: *const u8, data: *const *const ()) {
send(&RpcSend {
async: true,
service: service,
tag: tag,
tag: tag.as_ref(),
data: data
})
})
@ -206,21 +198,18 @@ extern fn watchdog_clear(id: i32) {
send(&WatchdogClear { id: id as usize })
}
extern fn cache_get(key: *const u8) -> CSlice<'static, i32> {
extern { fn strlen(s: *const c_char) -> size_t; }
let key = unsafe { slice::from_raw_parts(key, strlen(key as *const c_char)) };
let key = unsafe { str::from_utf8_unchecked(key) };
send(&CacheGetRequest { key: key });
extern fn cache_get(key: CSlice<u8>) -> CSlice<'static, i32> {
send(&CacheGetRequest {
key: str::from_utf8(key.as_ref()).unwrap()
});
recv!(&CacheGetReply { value } => value.as_c_slice())
}
extern fn cache_put(key: *const u8, list: CSlice<i32>) {
extern { fn strlen(s: *const c_char) -> size_t; }
let key = unsafe { slice::from_raw_parts(key, strlen(key as *const c_char)) };
let key = unsafe { str::from_utf8_unchecked(key) };
send(&CachePutRequest { key: key, value: list.as_ref() });
extern fn cache_put(key: CSlice<u8>, list: CSlice<i32>) {
send(&CachePutRequest {
key: str::from_utf8(key.as_ref()).unwrap(),
value: list.as_ref()
});
recv!(&CachePutReply { succeeded } => {
if !succeeded {
artiq_raise!("CacheError", "cannot put into a busy cache row")
@ -249,8 +238,8 @@ extern fn i2c_read(busno: i32, ack: bool) -> i32 {
unsafe fn attribute_writeback(typeinfo: *const ()) {
struct Attr {
offset: usize,
tag: *const u8,
name: *const u8
tag: CSlice<'static, u8>,
name: CSlice<'static, u8>
}
struct Type {
@ -276,7 +265,7 @@ unsafe fn attribute_writeback(typeinfo: *const ()) {
let attribute = *attributes;
attributes = attributes.offset(1);
if !(*attribute).tag.is_null() {
if (*attribute).tag.len() > 0 {
send_async_rpc(0, (*attribute).tag, [
&object as *const _ as *const (),
&(*attribute).name as *const _ as *const (),

View File

@ -1,5 +1,3 @@
#![allow(dead_code)] // FIXME
#![feature(allocator)]
#![no_std]
#![allocator]

View File

@ -1,4 +1,4 @@
#![feature(lang_items, asm, alloc, collections, libc, needs_panic_runtime,
#![feature(lang_items, asm, alloc, collections, needs_panic_runtime,
unicode, raw, int_error_internals, try_from, macro_reexport,
allow_internal_unstable, stmt_expr_attributes)]
#![no_std]
@ -9,7 +9,6 @@ extern crate alloc;
#[macro_use]
#[macro_reexport(vec, format)]
extern crate collections;
extern crate libc;
pub use core::{any, cell, clone, cmp, convert, default, hash, iter, marker, mem, num,
ops, option, ptr, result, sync,

View File

@ -17,6 +17,7 @@ compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-built
alloc_artiq = { path = "../liballoc_artiq" }
std_artiq = { path = "../libstd_artiq", features = ["alloc"] }
logger_artiq = { path = "../liblogger_artiq" }
cslice = { version = "0.3" }
log = { version = "0.3", default-features = false, features = ["max_level_debug"] }
board = { path = "../libboard", features = ["uart_console"] }
fringe = { version = "= 1.1.0", default-features = false, features = ["alloc"] }

View File

@ -1,6 +1,5 @@
#![allow(dead_code)]
use core::marker::PhantomData;
use core::fmt;
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40800000;
@ -11,14 +10,13 @@ pub const KSUPPORT_HEADER_SIZE: usize = 0x80;
#[repr(C)]
#[derive(Debug, Clone)]
pub struct Exception<'a> {
pub name: *const u8,
pub file: *const u8,
pub name: &'a str,
pub file: &'a str,
pub line: u32,
pub column: u32,
pub function: *const u8,
pub message: *const u8,
pub param: [i64; 3],
pub phantom: PhantomData<&'a str>
pub function: &'a str,
pub message: &'a str,
pub param: [i64; 3]
}
#[derive(Debug)]

View File

@ -6,6 +6,7 @@ extern crate alloc_artiq;
#[macro_use]
extern crate std_artiq as std;
extern crate libc;
extern crate cslice;
#[macro_use]
extern crate log;
extern crate logger_artiq;

View File

@ -1,7 +1,8 @@
#![allow(dead_code)]
use core::slice;
use core::str;
use std::io::{self, Read, Write};
use cslice::{CSlice, CMutSlice};
use proto::*;
use self::tag::{Tag, TagIterator, split_tag};
@ -30,11 +31,10 @@ unsafe fn recv_value(reader: &mut Read, tag: Tag, data: &mut *mut (),
*ptr = read_u64(reader)?; Ok(())
}),
Tag::String => {
consume_value!(*mut u8, |ptr| {
let length = read_u32(reader)?;
// NB: the received string includes a trailing \0
*ptr = alloc(length as usize)? as *mut u8;
reader.read_exact(slice::from_raw_parts_mut(*ptr, length as usize))?;
consume_value!(CMutSlice<u8>, |ptr| {
let length = read_u32(reader)? as usize;
*ptr = CMutSlice::new(alloc(length)? as *mut u8, length);
reader.read_exact((*ptr).as_mut())?;
Ok(())
})
}
@ -86,12 +86,6 @@ pub fn recv_return(reader: &mut Read, tag_bytes: &[u8], data: *mut (),
Ok(())
}
pub unsafe fn from_c_str<'a>(ptr: *const u8) -> &'a str {
use core::{str, slice};
extern { fn strlen(ptr: *const u8) -> usize; }
str::from_utf8_unchecked(slice::from_raw_parts(ptr as *const u8, strlen(ptr)))
}
unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::Result<()> {
macro_rules! consume_value {
($ty:ty, |$ptr:ident| $map:expr) => ({
@ -114,8 +108,8 @@ unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::
consume_value!(u64, |ptr|
write_u64(writer, *ptr)),
Tag::String =>
consume_value!(*const u8, |ptr|
write_string(writer, from_c_str(*ptr))),
consume_value!(CSlice<u8>, |ptr|
write_string(writer, str::from_utf8_unchecked((*ptr).as_ref()))),
Tag::Tuple(it, arity) => {
let mut it = it.clone();
write_u8(writer, arity)?;
@ -145,9 +139,9 @@ unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::
Ok(())
}
Tag::Keyword(it) => {
struct Keyword { name: *const u8, contents: () };
struct Keyword<'a> { name: CSlice<'a, u8>, contents: () };
consume_value!(Keyword, |ptr| {
write_string(writer, from_c_str((*ptr).name))?;
write_string(writer, str::from_utf8_unchecked((*ptr).name.as_ref()))?;
let tag = it.clone().next().expect("truncated tag");
let mut data = &(*ptr).contents as *const ();
send_value(writer, tag, &mut data)

View File

@ -62,8 +62,7 @@ struct Session<'a> {
congress: &'a mut Congress,
kernel_state: KernelState,
watchdog_set: board::clock::WatchdogSet,
log_buffer: String,
interner: BTreeSet<String>
log_buffer: String
}
impl<'a> Session<'a> {
@ -72,8 +71,7 @@ impl<'a> Session<'a> {
congress: congress,
kernel_state: KernelState::Absent,
watchdog_set: board::clock::WatchdogSet::new(),
log_buffer: String::new(),
interner: BTreeSet::new()
log_buffer: String::new()
}
}
@ -183,6 +181,7 @@ unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> io::Resul
Ok(())
}
&kern::LoadReply(Err(error)) => {
kernel::stop();
Err(io::Error::new(io::ErrorKind::Other,
format!("cannot load kernel: {}", error)))
}
@ -332,22 +331,14 @@ fn process_host_message(io: &Io,
}
})?;
// FIXME: gross.
fn into_c_str(interner: &mut BTreeSet<String>, s: String) -> *const u8 {
let s = s + "\0";
interner.insert(s.clone());
let p = interner.get(&s).unwrap().as_bytes().as_ptr();
p
}
let exn = kern::Exception {
name: into_c_str(&mut session.interner, name),
message: into_c_str(&mut session.interner, message),
param: param,
file: into_c_str(&mut session.interner, file),
line: line,
column: column,
function: into_c_str(&mut session.interner, function),
phantom: ::core::marker::PhantomData
name: name.as_ref(),
message: message.as_ref(),
param: param,
file: file.as_ref(),
line: line,
column: column,
function: function.as_ref()
};
kern_send(io, &kern::RpcRecvReply(Err(exn)))?;
@ -513,40 +504,33 @@ fn process_kern_message(io: &Io,
}
}
&kern::RunException { exception: ref exn, backtrace } => {
&kern::RunException {
exception: kern::Exception { name, message, param, file, line, column, function },
backtrace
} => {
unsafe { kernel::stop() }
session.kernel_state = KernelState::Absent;
unsafe { session.congress.cache.unborrow() }
unsafe fn from_c_str<'a>(s: *const u8) -> &'a str {
use ::libc::{c_char, size_t};
use core::slice;
extern { fn strlen(s: *const c_char) -> size_t; }
let s = slice::from_raw_parts(s, strlen(s as *const c_char));
str::from_utf8_unchecked(s)
}
let name = unsafe { from_c_str(exn.name) };
let message = unsafe { from_c_str(exn.message) };
let file = unsafe { from_c_str(exn.file) };
let function = unsafe { from_c_str(exn.function) };
match stream {
None => {
error!("exception in flash kernel");
error!("{}: {} {:?}", name, message, exn.param);
error!("at {}:{}:{} in {}", file, exn.line, exn.column, function);
error!("{}: {} {:?}", name, message, param);
error!("at {}:{}:{} in {}", file, line, column, function);
return Ok(true)
},
Some(ref mut stream) =>
Some(ref mut stream) => {
host_write(stream, host::Reply::KernelException {
name: name,
message: message,
param: exn.param,
file: file,
line: exn.line,
column: exn.column,
function: function,
name: name,
message: message,
param: param,
file: file,
line: line,
column: column,
function: function,
backtrace: backtrace
})
}
}
}

View File

@ -230,18 +230,19 @@ static _Unwind_Reason_Code __artiq_uncaught_exception(
void *stop_parameter);
struct artiq_raised_exception {
struct _Unwind_Exception unwind;
struct artiq_exception artiq;
int handled;
struct _Unwind_Exception unwind;
struct artiq_exception artiq;
int handled;
uintptr_t backtrace[1024];
size_t backtrace_size;
size_t backtrace_size;
};
static struct artiq_raised_exception inflight;
void __artiq_raise(struct artiq_exception *artiq_exn) {
EH_LOG("===> raise (name=%s, msg=%s, params=[%lld,%lld,%lld])",
artiq_exn->name, artiq_exn->message,
EH_LOG("===> raise (name=%.*s, msg=%.*s, params=[%lld,%lld,%lld])",
(int)artiq_exn->name.len, (const char*)artiq_exn->name.ptr,
(int)artiq_exn->name.len, (const char*)artiq_exn->message.ptr,
(long long int)artiq_exn->param[0],
(long long int)artiq_exn->param[1],
(long long int)artiq_exn->param[2]);
@ -269,8 +270,6 @@ void __artiq_reraise() {
__artiq_raise(&inflight.artiq);
} else {
EH_LOG0("===> resume");
EH_ASSERT((inflight.artiq.typeinfo != 0) &&
"Need an exception to reraise");
_Unwind_Resume(&inflight.unwind);
abort();
}
@ -333,8 +332,8 @@ _Unwind_Reason_Code __artiq_personality(
struct artiq_raised_exception *inflight =
(struct artiq_raised_exception*)exceptionObject;
EH_LOG("=> exception name=%s",
inflight->artiq.name);
EH_LOG("=> exception name=%.*s",
(int)inflight->artiq.name.len, (const char*)inflight->artiq.name.ptr);
// Get a pointer to LSDA. If there's no LSDA, this function doesn't
// actually handle any exceptions.
@ -418,13 +417,17 @@ _Unwind_Reason_Code __artiq_personality(
if(typeInfoOffset > 0) {
unsigned encodingSize = getEncodingSize(ttypeEncoding);
const uint8_t *typeInfoPtrPtr = classInfo - typeInfoOffset * encodingSize;
uintptr_t typeInfoPtr = readEncodedPointer(&typeInfoPtrPtr, ttypeEncoding);
const struct slice *typeInfoPtr =
(const struct slice *)readEncodedPointer(&typeInfoPtrPtr, ttypeEncoding);
EH_LOG("encodingSize=%u typeInfoPtrPtr=%p typeInfoPtr=%p",
encodingSize, typeInfoPtrPtr, (void*)typeInfoPtr);
EH_LOG("typeInfo=%s", (char*)typeInfoPtr);
if(typeInfoPtr != NULL) {
EH_LOG("typeInfo=%.*s", (int)typeInfoPtr->len, (const char *)typeInfoPtr->ptr);
}
if(typeInfoPtr == 0 || !strcmp((char*)inflight->artiq.typeinfo,
(char*)typeInfoPtr)) {
if(typeInfoPtr == NULL ||
(inflight->artiq.name.len == typeInfoPtr->len &&
!memcmp(inflight->artiq.name.ptr, typeInfoPtr->ptr, typeInfoPtr->len))) {
EH_LOG0("matching action found");
exceptionMatched = 1;
break;

View File

@ -10,16 +10,13 @@ struct slice {
};
struct artiq_exception {
union {
uintptr_t typeinfo;
const char *name;
};
const char *file;
int32_t line;
int32_t column;
const char *function;
const char *message;
int64_t param[3];
struct slice name;
struct slice file;
int32_t line;
int32_t column;
struct slice function;
struct slice message;
int64_t param[3];
};
#ifdef __cplusplus
@ -32,20 +29,6 @@ void __artiq_raise(struct artiq_exception *artiq_exn)
void __artiq_reraise(void)
__attribute__((noreturn));
#define artiq_raise_from_c(exnname, exnmsg, exnparam0, exnparam1, exnparam2) \
do { \
struct artiq_exception exn = { \
.name = "0:artiq.coredevice.exceptions." exnname, \
.message = exnmsg, \
.param = { exnparam0, exnparam1, exnparam2 }, \
.file = __FILE__, \
.line = __LINE__, \
.column = -1, \
.function = __func__, \
}; \
__artiq_raise(&exn); \
} while(0)
/* Called by the runtime */
void __artiq_terminate(struct artiq_exception *artiq_exn,
struct slice backtrace)

View File

@ -9,11 +9,14 @@
void __artiq_terminate(struct artiq_exception *exn,
struct slice backtrace) {
printf("Uncaught %s: %s (%"PRIi64", %"PRIi64", %"PRIi64")\n"
"at %s:%"PRIi32":%"PRIi32"\n",
exn->name, exn->message,
printf("Uncaught %.*s: %.*s (%"PRIi64", %"PRIi64", %"PRIi64")\n"
"at %.*s:%"PRIi32":%"PRIi32"\n",
(int)exn->name.len, (const char *)exn->name.ptr,
(int)exn->message.len, (const char *)exn->message.ptr,
exn->param[0], exn->param[1], exn->param[1],
exn->file, exn->line, exn->column + 1);
(int)exn->file.len, (const char *)exn->file.ptr,
exn->line,
exn->column + 1);
for(size_t i = 0; i < backtrace.len; i++) {
printf("at %"PRIxPTR"\n", ((uintptr_t*)backtrace.ptr)[i]);

View File

@ -1,4 +1,5 @@
# RUN: %python -m artiq.compiler.testbench.jit %s
# RUN: %python %s
assert "xy" == "xy"
assert ("x" + "y") == "xy"