forked from M-Labs/artiq
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:
parent
e13d8919ff
commit
fd8b11532f
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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()))
|
||||
|
1
artiq/firmware/Cargo.lock
generated
1
artiq/firmware/Cargo.lock
generated
@ -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",
|
||||
|
@ -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),
|
||||
|
@ -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 (),
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![allow(dead_code)] // FIXME
|
||||
|
||||
#![feature(allocator)]
|
||||
#![no_std]
|
||||
#![allocator]
|
||||
|
@ -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,
|
||||
|
@ -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"] }
|
||||
|
@ -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)]
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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]);
|
||||
|
@ -1,4 +1,5 @@
|
||||
# RUN: %python -m artiq.compiler.testbench.jit %s
|
||||
# RUN: %python %s
|
||||
|
||||
assert "xy" == "xy"
|
||||
assert ("x" + "y") == "xy"
|
||||
|
Loading…
Reference in New Issue
Block a user