Skip to content

Commit

Permalink
Add zero-cost exception support to runtime and host.
Browse files Browse the repository at this point in the history
  • Loading branch information
whitequark committed Aug 8, 2015
1 parent 1d61e44 commit 27d2390
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 67 deletions.
1 change: 1 addition & 0 deletions artiq/compiler/builtins.py
Expand Up @@ -86,6 +86,7 @@ class TException(types.TMono):
("__file__", TStr()),
("__line__", TInt(types.TValue(32))),
("__col__", TInt(types.TValue(32))),
("__func__", TStr()),
("__message__", TStr()),
("__param0__", TInt(types.TValue(64))),
("__param1__", TInt(types.TValue(64))),
Expand Down
5 changes: 4 additions & 1 deletion artiq/compiler/transforms/artiq_ir_generator.py
Expand Up @@ -157,7 +157,7 @@ def visit_ModuleT(self, node):

def visit_function(self, node, is_lambda, is_internal):
if is_lambda:
name = "lambda.{}.{}".format(node.loc.line(), node.loc.column())
name = "lambda@{}:{}".format(node.loc.line(), node.loc.column())
typ = node.type.find()
else:
name = node.name
Expand Down Expand Up @@ -471,9 +471,11 @@ def raise_exn(self, exn):
loc_file = ir.Constant(self.current_loc.source_buffer.name, builtins.TStr())
loc_line = ir.Constant(self.current_loc.line(), builtins.TInt(types.TValue(32)))
loc_column = ir.Constant(self.current_loc.column(), builtins.TInt(types.TValue(32)))
loc_function = ir.Constant(".".join(self.name), builtins.TStr())
self.append(ir.SetAttr(exn, "__file__", loc_file))
self.append(ir.SetAttr(exn, "__line__", loc_line))
self.append(ir.SetAttr(exn, "__col__", loc_column))
self.append(ir.SetAttr(exn, "__func__", loc_function))

if self.unwind_target is not None:
self.append(ir.Raise(exn, self.unwind_target))
Expand Down Expand Up @@ -1237,6 +1239,7 @@ def alloc_exn(self, typ, message=None, param0=None, param1=None, param2=None):
ir.Constant("<not thrown>", builtins.TStr()), # file
ir.Constant(0, builtins.TInt(types.TValue(32))), # line
ir.Constant(0, builtins.TInt(types.TValue(32))), # column
ir.Constant("<not thrown>", builtins.TStr()), # function
]

if message is None:
Expand Down
118 changes: 83 additions & 35 deletions artiq/coredevice/comm_generic.py
@@ -1,5 +1,6 @@
import struct
import logging
import traceback
from enum import Enum
from fractions import Fraction

Expand All @@ -18,11 +19,12 @@ class _H2DMsgType(Enum):
RUN_KERNEL = 5

RPC_REPLY = 6
RPC_EXCEPTION = 7

FLASH_READ_REQUEST = 7
FLASH_WRITE_REQUEST = 8
FLASH_ERASE_REQUEST = 9
FLASH_REMOVE_REQUEST = 10
FLASH_READ_REQUEST = 8
FLASH_WRITE_REQUEST = 9
FLASH_ERASE_REQUEST = 10
FLASH_REMOVE_REQUEST = 11


class _D2HMsgType(Enum):
Expand Down Expand Up @@ -223,16 +225,12 @@ def switch_clock(self, external):

self._read_empty(_D2HMsgType.CLOCK_SWITCH_COMPLETED)

def load(self, kernel_library):
self._write_header(_H2DMsgType.LOAD_LIBRARY)
self._write_chunk(kernel_library)
self._write_flush()

self._read_empty(_D2HMsgType.LOAD_COMPLETED)
def get_log(self):
self._write_empty(_H2DMsgType.LOG_REQUEST)

def run(self):
self._write_empty(_H2DMsgType.RUN_KERNEL)
logger.debug("running kernel")
self._read_header()
self._read_expect(_D2HMsgType.LOG_REPLY)
return self._read_chunk(self._read_length).decode('utf-8')

def flash_storage_read(self, key):
self._write_header(_H2DMsgType.FLASH_READ_REQUEST)
Expand Down Expand Up @@ -267,7 +265,18 @@ def flash_storage_remove(self, key):

self._read_empty(_D2HMsgType.FLASH_OK_REPLY)

def _receive_rpc_value(self, tag):
def load(self, kernel_library):
self._write_header(_H2DMsgType.LOAD_LIBRARY)
self._write_chunk(kernel_library)
self._write_flush()

self._read_empty(_D2HMsgType.LOAD_COMPLETED)

def run(self):
self._write_empty(_H2DMsgType.RUN_KERNEL)
logger.debug("running kernel")

def _receive_rpc_value(self, tag, rpc_map):
if tag == "n":
return None
elif tag == "b":
Expand All @@ -286,37 +295,83 @@ def _receive_rpc_value(self, tag):
elt_tag = chr(self._read_int8())
length = self._read_int32()
return [self._receive_rpc_value(elt_tag) for _ in range(length)]
elif tag == "o":
return rpc_map[self._read_int32()]
else:
raise IOError("Unknown RPC value tag: {}", tag)

def _receive_rpc_values(self):
def _receive_rpc_values(self, rpc_map):
result = []
while True:
tag = chr(self._read_int8())
if tag == "\x00":
return result
else:
result.append(self._receive_rpc_value(tag))
result.append(self._receive_rpc_value(tag, rpc_map))

def _serve_rpc(self, rpc_map):
service = self._read_int32()
args = self._receive_rpc_values()
args = self._receive_rpc_values(rpc_map)
logger.debug("rpc service: %d %r", service, args)

eid, result = rpc_wrapper.run_rpc(rpc_map[rpc_num], args)
logger.debug("rpc service: %d %r == %r (eid %d)", service, args,
result, eid)
try:
result = rpc_map[rpc_num](args)
if not isinstance(result, int) or not (-2**31 < result < 2**31-1):
raise ValueError("An RPC must return an int(width=32)")
except ARTIQException as exn:
logger.debug("rpc service: %d %r ! %r", service, args, exn)

self._write_header(_H2DMsgType.RPC_EXCEPTION)
self._write_string(exn.name)
self._write_string(exn.message)
for index in range(3):
self._write_int64(exn.param[index])

self._write_string(exn.filename)
self._write_int32(exn.line)
self._write_int32(exn.column)
self._write_string(exn.function)

self._write_flush()
except Exception as exn:
logger.debug("rpc service: %d %r ! %r", service, args, exn)

self._write_header(_H2DMsgType.RPC_EXCEPTION)
self._write_string(type(exn).__name__)
self._write_string(str(exn))
for index in range(3):
self._write_int64(0)

((filename, line, function, _), ) = traceback.extract_tb(exn.__traceback__)
self._write_string(filename)
self._write_int32(line)
self._write_int32(-1) # column not known
self._write_string(function)

self._write_flush()
else:
logger.debug("rpc service: %d %r == %r", service, args, result)

self._write_header(_H2DMsgType.RPC_REPLY)
self._write_int32(eid)
self._write_int32(result)
self._write_flush()
self._write_header(_H2DMsgType.RPC_REPLY)
self._write_int32(result)
self._write_flush()

def _serve_exception(self):
eid = self._read_int32()
params = [self._read_int64() for _ in range(3)]
rpc_wrapper.filter_rpc_exception(eid)
raise exception(self.core, *params)
name = self._read_string()
message = self._read_string()
params = [self._read_int64() for _ in range(3)]

filename = self._read_string()
line = self._read_int32()
column = self._read_int32()
function = self._read_string()

backtrace = [self._read_int32() for _ in range(self._read_int32())]
# we don't have debug information yet.
# print("exception backtrace:", [hex(x) for x in backtrace])

raise core_language.ARTIQException(name, message, params,
filename, line, column, function)

def serve(self, rpc_map):
while True:
Expand All @@ -328,10 +383,3 @@ def serve(self, rpc_map):
else:
self._read_expect(_D2HMsgType.KERNEL_FINISHED)
return

def get_log(self):
self._write_empty(_H2DMsgType.LOG_REQUEST)

self._read_header()
self._read_expect(_D2HMsgType.LOG_REPLY)
return self._read_chunk(self._read_length).decode('utf-8')
8 changes: 8 additions & 0 deletions artiq/coredevice/exceptions.py
@@ -1,5 +1,13 @@
from artiq.language.core import ARTIQException

class ZeroDivisionError(ARTIQException):
"""Python's :class:`ZeroDivisionError`, mirrored in ARTIQ."""

class ValueError(ARTIQException):
"""Python's :class:`ValueError`, mirrored in ARTIQ."""

class IndexError(ARTIQException):
"""Python's :class:`IndexError`, mirrored in ARTIQ."""

class InternalError(ARTIQException):
"""Raised when the runtime encounters an internal error condition."""
Expand Down
27 changes: 22 additions & 5 deletions artiq/language/core.py
Expand Up @@ -2,6 +2,7 @@
Core ARTIQ extensions to the Python language.
"""

import linecache
from collections import namedtuple
from functools import wraps

Expand Down Expand Up @@ -278,7 +279,8 @@ class ARTIQException(Exception):
"""Base class for exceptions raised or passed through the core device."""

# Try and create an instance of the specific class, if one exists.
def __new__(cls, name, message, params):
def __new__(cls, name, message,
params, filename, line, column, function):
def find_subclass(cls):
if cls.__name__ == name:
return cls
Expand All @@ -293,15 +295,30 @@ def find_subclass(cls):
more_specific_cls = cls

exn = Exception.__new__(more_specific_cls)
exn.__init__(name, message, params)
exn.__init__(name, message, params,
filename, line, column, function)
return exn

def __init__(self, name, message, params):
def __init__(self, name, message, params,
filename, line, column, function):
Exception.__init__(self, name, message, *params)
self.name, self.message, self.params = name, message, params
self.filename, self.line, self.column = filename, line, column
self.function = function

def __str__(self):
lines = []

if type(self).__name__ == self.name:
return self.message.format(*self.params)
lines.append(self.message.format(*self.params))
else:
return "({}) {}".format(self.name, self.message.format(*self.params))
lines.append("({}) {}".format(self.name, self.message.format(*self.params)))

lines.append("Core Device Traceback (most recent call last):")
lines.append(" File \"{file}\", line {line}, column {column}, in {function}".
format(file=self.filename, line=self.line, column=self.column + 1,
function=self.function))
line = linecache.getline(self.filename, self.line)
lines.append(" {}".format(line.strip() if line else "<unknown>"))

return "\n".join(lines)
1 change: 1 addition & 0 deletions soc/runtime/artiq_personality.h
Expand Up @@ -12,6 +12,7 @@ struct artiq_exception {
const char *file;
int32_t line;
int32_t column;
const char *function;
const char *message;
int64_t param[3];
};
Expand Down
20 changes: 18 additions & 2 deletions soc/runtime/kloader.c
Expand Up @@ -30,7 +30,7 @@ void kloader_start_bridge()
start_kernel_cpu(NULL);
}

static int load_or_start_kernel(void *library, int run_kernel)
static int load_or_start_kernel(const void *library, int run_kernel)
{
static struct dyld_info library_info;
struct msg_load_request request = {
Expand All @@ -56,7 +56,7 @@ static int load_or_start_kernel(void *library, int run_kernel)
return 1;
}

int kloader_load_library(void *library)
int kloader_load_library(const void *library)
{
if(!kernel_cpu_reset_read()) {
log("BUG: attempted to load kernel library while kernel CPU is running");
Expand All @@ -66,6 +66,22 @@ int kloader_load_library(void *library)
return load_or_start_kernel(library, 0);
}

void kloader_filter_backtrace(struct artiq_backtrace_item *backtrace,
size_t *backtrace_size) {
struct artiq_backtrace_item *cursor = backtrace;

// Remove all backtrace items belonging to ksupport and subtract
// shared object base from the addresses.
for(int i = 0; i < *backtrace_size; i++) {
if(backtrace[i].function > KERNELCPU_PAYLOAD_ADDRESS) {
backtrace[i].function -= KERNELCPU_PAYLOAD_ADDRESS;
*cursor++ = backtrace[i];
}
}

*backtrace_size = cursor - backtrace;
}

void kloader_start_kernel()
{
load_or_start_kernel(NULL, 1);
Expand Down
6 changes: 5 additions & 1 deletion soc/runtime/kloader.h
@@ -1,14 +1,18 @@
#ifndef __KLOADER_H
#define __KLOADER_H

#include "artiq_personality.h"

#define KERNELCPU_EXEC_ADDRESS 0x40400000
#define KERNELCPU_PAYLOAD_ADDRESS 0x40420000
#define KERNELCPU_LAST_ADDRESS (0x4fffffff - 1024*1024)
#define KSUPPORT_HEADER_SIZE 0x80

extern long long int now;

int kloader_load_library(void *code);
int kloader_load_library(const void *code);
void kloader_filter_backtrace(struct artiq_backtrace_item *backtrace,
size_t *backtrace_size);

void kloader_start_bridge(void);
int kloader_start_idle_kernel(void);
Expand Down

0 comments on commit 27d2390

Please sign in to comment.