mirror of https://github.com/m-labs/artiq.git
Implement selective attribute writeback using shadow memory.
This commit is contained in:
parent
2e33084a5f
commit
38a99fde52
|
@ -89,13 +89,13 @@ class TException(types.TMono):
|
|||
attributes = OrderedDict([
|
||||
("__name__", TStr()),
|
||||
("__file__", TStr()),
|
||||
("__line__", TInt(types.TValue(32))),
|
||||
("__col__", TInt(types.TValue(32))),
|
||||
("__line__", TInt32()),
|
||||
("__col__", TInt32()),
|
||||
("__func__", TStr()),
|
||||
("__message__", TStr()),
|
||||
("__param0__", TInt(types.TValue(64))),
|
||||
("__param1__", TInt(types.TValue(64))),
|
||||
("__param2__", TInt(types.TValue(64))),
|
||||
("__param0__", TInt64()),
|
||||
("__param1__", TInt64()),
|
||||
("__param2__", TInt64()),
|
||||
])
|
||||
|
||||
def __init__(self, name="Exception", id=0):
|
||||
|
@ -191,6 +191,12 @@ def is_int(typ, width=None):
|
|||
else:
|
||||
return types.is_mono(typ, "int")
|
||||
|
||||
def is_int32(typ):
|
||||
return is_int(typ, types.TValue(32))
|
||||
|
||||
def is_int64(typ):
|
||||
return is_int(typ, types.TValue(64))
|
||||
|
||||
def get_int_width(typ):
|
||||
if is_int(typ):
|
||||
return types.get_value(typ.find()["width"])
|
||||
|
|
|
@ -81,8 +81,14 @@ class Target:
|
|||
print(function.as_entity(type_printer), file=sys.stderr)
|
||||
|
||||
llmod = module.build_llvm_ir(self)
|
||||
llparsedmod = llvm.parse_assembly(str(llmod))
|
||||
llparsedmod.verify()
|
||||
|
||||
try:
|
||||
llparsedmod = llvm.parse_assembly(str(llmod))
|
||||
llparsedmod.verify()
|
||||
except RuntimeError:
|
||||
print("====== LLVM IR DUMP (PARSE FAILED) ======", file=sys.stderr)
|
||||
print(str(llmod), file=sys.stderr)
|
||||
raise
|
||||
|
||||
if os.getenv("ARTIQ_DUMP_LLVM"):
|
||||
print("====== LLVM IR DUMP ======", file=sys.stderr)
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
into LLVM intermediate representation.
|
||||
"""
|
||||
|
||||
import os, re
|
||||
import os, re, types as pytypes
|
||||
from collections import defaultdict
|
||||
from pythonparser import ast, diagnostic
|
||||
from llvmlite_artiq import ir as ll
|
||||
from llvmlite_artiq import ir as ll, binding as llvm
|
||||
from ...language import core as language_core
|
||||
from .. import types, builtins, ir
|
||||
|
||||
|
@ -418,11 +418,21 @@ class LLVMIRGenerator:
|
|||
return self.llmodule
|
||||
|
||||
def emit_attribute_writeback(self):
|
||||
llobjects = []
|
||||
shadow_memory_dim = defaultdict(lambda: 0)
|
||||
|
||||
for obj_id in self.object_map:
|
||||
while len(llobjects) <= obj_id:
|
||||
llobjects.append(ll.Constant(llptr, None))
|
||||
|
||||
llobject = self.llmodule.get_global("object.{}".format(obj_id))
|
||||
if llobject is not None:
|
||||
llobjects[obj_id] = llobject.bitcast(llptr)
|
||||
|
||||
obj_ref = self.object_map.retrieve(obj_id)
|
||||
if isinstance(obj_ref, type):
|
||||
if isinstance(obj_ref, (pytypes.FunctionType, pytypes.MethodType)):
|
||||
continue
|
||||
elif isinstance(obj_ref, type):
|
||||
_, typ = self.type_map[obj_ref]
|
||||
else:
|
||||
typ, _ = self.type_map[type(obj_ref)]
|
||||
|
@ -430,14 +440,18 @@ class LLVMIRGenerator:
|
|||
if shadow_memory_dim[typ] <= obj_id:
|
||||
shadow_memory_dim[typ] = obj_id + 1
|
||||
|
||||
lldatalayout = llvm.create_target_data(self.llmodule.data_layout)
|
||||
|
||||
llrpcattrty = self.llcontext.get_identified_type("shadow.attr")
|
||||
llrpcattrty.elements = [lli32, llptr, llptr]
|
||||
|
||||
lldescty = self.llcontext.get_identified_type("shadow.desc")
|
||||
lldescty.elements = [llptr.as_pointer(), llptr, lli32, llptr]
|
||||
lldescty.elements = [llrpcattrty.as_pointer().as_pointer(), lli32, llptr]
|
||||
|
||||
lldescs = []
|
||||
for typ in shadow_memory_dim:
|
||||
if "__objectid__" not in typ.attributes:
|
||||
continue
|
||||
assert list(typ.attributes.keys())[0] == "__objectid__"
|
||||
|
||||
if types.is_constructor(typ):
|
||||
type_name = "class.{}".format(typ.name)
|
||||
|
@ -455,44 +469,72 @@ class LLVMIRGenerator:
|
|||
llshadow.type = llshadowty.as_pointer()
|
||||
llshadow.initializer = ll.Constant(llshadowty, None)
|
||||
|
||||
def rpc_tag_error(typ):
|
||||
print(typ)
|
||||
assert False
|
||||
def llrpcattr_of_attr(name, typ):
|
||||
llty = self.llty_of_type(typ)
|
||||
if isinstance(llty, ll.PointerType):
|
||||
# Work around llvmlite bug where it is unable to get a C++
|
||||
# object for a type if it includes an identified type in a context
|
||||
# other than the default.
|
||||
size = llptr.get_abi_size(lldatalayout)
|
||||
else:
|
||||
size = llty.get_abi_size(lldatalayout)
|
||||
|
||||
rpcattrary = list(typ.attributes.keys())[1:]
|
||||
llrpcattraryty = ll.ArrayType(llptr, len(rpcattrary) + 1)
|
||||
llrpcattrary = list(map(lambda attr: self.llstr_of_str(attr), rpcattrary))
|
||||
def rpc_tag_error(typ):
|
||||
print(typ)
|
||||
assert False
|
||||
|
||||
llrpcattrs = ll.GlobalVariable(self.llmodule, llrpcattraryty,
|
||||
name="shadow.attrs.{}".format(type_name))
|
||||
llrpcattrs.initializer = ll.Constant(llrpcattraryty,
|
||||
llrpcattrary + [ll.Constant(llptr, None)])
|
||||
llrpcattrs.linkage = 'internal'
|
||||
rpctag = b"Os"
|
||||
if not (types.is_function(typ) or types.is_method(typ)):
|
||||
rpctag += self._rpc_tag(typ, error_handler=rpc_tag_error)
|
||||
else:
|
||||
rpctag += b""
|
||||
rpctag += b":n\x00"
|
||||
llrpctag = self.llstr_of_str(rpctag)
|
||||
|
||||
rpctag = b""
|
||||
for attr_type in list(typ.attributes.values())[1:]:
|
||||
if types.is_function(attr_type) or types.is_method(attr_type):
|
||||
continue
|
||||
rpctag += self._rpc_tag(attr_type, error_handler=rpc_tag_error)
|
||||
rpctag += b"\x00"
|
||||
llrpctag = self.llstr_of_str(rpctag)
|
||||
llrpcattr = ll.GlobalVariable(self.llmodule, llrpcattrty,
|
||||
name="shadow.attr.{}.{}".format(type_name, name))
|
||||
llrpcattr.initializer = ll.Constant(llrpcattrty, [
|
||||
ll.Constant(lli32, size),
|
||||
self.llstr_of_str(rpctag),
|
||||
self.llstr_of_str(name)
|
||||
])
|
||||
llrpcattr.global_constant = True
|
||||
llrpcattr.unnamed_addr = True
|
||||
llrpcattr.linkage = 'internal'
|
||||
|
||||
return llrpcattr
|
||||
|
||||
llrpcattrs = [llrpcattr_of_attr(attr, typ.attributes[attr])
|
||||
for attr in typ.attributes]
|
||||
|
||||
llrpcattraryty = ll.ArrayType(llrpcattrty.as_pointer(), len(llrpcattrs) + 1)
|
||||
llrpcattrary = ll.GlobalVariable(self.llmodule, llrpcattraryty,
|
||||
name="shadow.attrs.{}".format(type_name))
|
||||
llrpcattrary.initializer = ll.Constant(llrpcattraryty,
|
||||
llrpcattrs + [ll.Constant(llrpcattrty.as_pointer(), None)])
|
||||
llrpcattrary.global_constant = True
|
||||
llrpcattrary.unnamed_addr = True
|
||||
llrpcattrary.linkage = 'internal'
|
||||
|
||||
lldesc = ll.GlobalVariable(self.llmodule, lldescty,
|
||||
name="shadow.desc.{}".format(type_name))
|
||||
lldesc.initializer = ll.Constant(lldescty, [
|
||||
llrpcattrs.bitcast(llptr.as_pointer()),
|
||||
llrpctag,
|
||||
llrpcattrary.bitcast(llrpcattrty.as_pointer().as_pointer()),
|
||||
ll.Constant(lli32, shadow_memory_dim[typ]),
|
||||
llshadow.bitcast(llptr)])
|
||||
llshadow.bitcast(llptr)
|
||||
])
|
||||
lldesc.global_constant = True
|
||||
lldesc.linkage = 'internal'
|
||||
lldescs.append(lldesc)
|
||||
|
||||
llglobaldescty = ll.ArrayType(lldescty.as_pointer(), len(lldescs) + 1)
|
||||
llglobaldesc = ll.GlobalVariable(self.llmodule, llglobaldescty,
|
||||
name="shadow.descs")
|
||||
llglobaldesc = ll.GlobalVariable(self.llmodule, llglobaldescty, name="shadow")
|
||||
llglobaldesc.initializer = ll.Constant(llglobaldescty,
|
||||
lldescs + [ll.Constant(lldescty.as_pointer(), None)])
|
||||
# llglobaldesc.linkage = 'internal'
|
||||
|
||||
llobjectaryty = ll.ArrayType(llptr, len(llobjects))
|
||||
llobjectary = ll.GlobalVariable(self.llmodule, llobjectaryty, name="objects")
|
||||
llobjectary.initializer = ll.Constant(llobjectaryty, llobjects)
|
||||
|
||||
def process_function(self, func):
|
||||
try:
|
||||
|
@ -661,10 +703,10 @@ class LLVMIRGenerator:
|
|||
llidptr = self.llbuilder.gep(self.map(insn.object()),
|
||||
[self.llindex(0), self.llindex(0)])
|
||||
llid = self.llbuilder.load(llidptr, name="shadow.id")
|
||||
llattrcount = ll.Constant(lli32, len(object_type.attributes) - 1)
|
||||
llattrcount = ll.Constant(lli32, len(object_type.attributes))
|
||||
llshadowpos = self.llbuilder.add(
|
||||
self.llbuilder.mul(llid, llattrcount),
|
||||
ll.Constant(lli32, self.attr_index(insn) - 1))
|
||||
ll.Constant(lli32, self.attr_index(insn)))
|
||||
|
||||
if types.is_constructor(object_type):
|
||||
shadowname = "shadow.class.{}".format(object_type.name)
|
||||
|
|
|
@ -435,7 +435,11 @@ class CommGeneric:
|
|||
|
||||
def _serve_rpc(self, object_map):
|
||||
service_id = self._read_int32()
|
||||
service = object_map.retrieve(service_id)
|
||||
if service_id == 0:
|
||||
service = lambda obj, attr, value: setattr(obj, attr, value)
|
||||
else:
|
||||
service = object_map.retrieve(service_id)
|
||||
|
||||
arguments = self._receive_rpc_args(object_map, service.__defaults__)
|
||||
return_tags = self._read_bytes()
|
||||
logger.debug("rpc service: [%d]%r %r -> %s", service_id, service, arguments, return_tags)
|
||||
|
@ -444,10 +448,11 @@ class CommGeneric:
|
|||
result = service(*arguments)
|
||||
logger.debug("rpc service: %d %r == %r", service_id, arguments, result)
|
||||
|
||||
self._write_header(_H2DMsgType.RPC_REPLY)
|
||||
self._write_bytes(return_tags)
|
||||
self._send_rpc_value(bytearray(return_tags), result, result, service)
|
||||
self._write_flush()
|
||||
if service_id != 0:
|
||||
self._write_header(_H2DMsgType.RPC_REPLY)
|
||||
self._write_bytes(return_tags)
|
||||
self._send_rpc_value(bytearray(return_tags), result, result, service)
|
||||
self._write_flush()
|
||||
except Exception as exn:
|
||||
logger.debug("rpc service: %d %r ! %r", service_id, arguments, exn)
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
double round(double x);
|
||||
|
||||
void ksupport_abort(void);
|
||||
static void attribute_writeback(void *, void *);
|
||||
|
||||
int64_t now;
|
||||
|
||||
|
@ -249,14 +250,22 @@ int main(void)
|
|||
}
|
||||
|
||||
if(request->run_kernel) {
|
||||
void (*kernel_init)() = request->library_info->init;
|
||||
void (*kernel_run)() = request->library_info->init;
|
||||
void *__bss_start = dyld_lookup("__bss_start", request->library_info);
|
||||
void *_end = dyld_lookup("_end", request->library_info);
|
||||
void *shadow = dyld_lookup("shadow", request->library_info);
|
||||
void *objects = dyld_lookup("objects", request->library_info);
|
||||
|
||||
memset(__bss_start, 0, _end - __bss_start);
|
||||
|
||||
mailbox_send_and_wait(&load_reply);
|
||||
|
||||
now = now_init();
|
||||
kernel_init();
|
||||
kernel_run();
|
||||
now_save(now);
|
||||
|
||||
attribute_writeback(shadow, objects);
|
||||
|
||||
struct msg_base finished_reply;
|
||||
finished_reply.type = MESSAGE_TYPE_FINISHED;
|
||||
mailbox_send_and_wait(&finished_reply);
|
||||
|
@ -357,7 +366,10 @@ void send_rpc(int service, const char *tag, ...)
|
|||
{
|
||||
struct msg_rpc_send request;
|
||||
|
||||
request.type = MESSAGE_TYPE_RPC_SEND;
|
||||
if(service != 0)
|
||||
request.type = MESSAGE_TYPE_RPC_SEND;
|
||||
else
|
||||
request.type = MESSAGE_TYPE_RPC_BATCH;
|
||||
request.service = service;
|
||||
request.tag = tag;
|
||||
va_start(request.args, tag);
|
||||
|
@ -393,6 +405,50 @@ int recv_rpc(void *slot) {
|
|||
}
|
||||
}
|
||||
|
||||
struct shadow_attr {
|
||||
uint32_t size;
|
||||
const char *tag;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct shadow_desc {
|
||||
struct shadow_attr **attributes;
|
||||
uint32_t object_count;
|
||||
uint8_t *shadow;
|
||||
};
|
||||
|
||||
void attribute_writeback(void *udescs, void *uobjects) {
|
||||
struct shadow_desc **descs = (struct shadow_desc **)udescs;
|
||||
void **objects = (void **)uobjects;
|
||||
|
||||
while(*descs) {
|
||||
struct shadow_desc *desc = *descs++;
|
||||
|
||||
size_t attr_count = 0;
|
||||
for(struct shadow_attr **attr = desc->attributes; *attr; attr++)
|
||||
attr_count++;
|
||||
|
||||
for(int object_id = 0; object_id < desc->object_count; object_id++) {
|
||||
uint8_t *shadow = &desc->shadow[object_id * attr_count];
|
||||
void *object = objects[object_id];
|
||||
|
||||
if(object == NULL) continue;
|
||||
|
||||
size_t offset = 0;
|
||||
for(int attr_index = 0; attr_index < attr_count; attr_index++) {
|
||||
struct shadow_attr *attr = desc->attributes[attr_index];
|
||||
|
||||
if(shadow[attr_index]) {
|
||||
uintptr_t value = (uintptr_t)object + offset;
|
||||
send_rpc(0, attr->tag, &object, &attr->name, value);
|
||||
}
|
||||
|
||||
offset += attr->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lognonl(const char *fmt, ...)
|
||||
{
|
||||
struct msg_log request;
|
||||
|
|
|
@ -17,6 +17,7 @@ enum {
|
|||
MESSAGE_TYPE_RPC_SEND,
|
||||
MESSAGE_TYPE_RPC_RECV_REQUEST,
|
||||
MESSAGE_TYPE_RPC_RECV_REPLY,
|
||||
MESSAGE_TYPE_RPC_BATCH,
|
||||
MESSAGE_TYPE_LOG,
|
||||
|
||||
MESSAGE_TYPE_BRG_READY,
|
||||
|
@ -97,6 +98,13 @@ struct msg_rpc_recv_reply {
|
|||
struct artiq_exception *exception;
|
||||
};
|
||||
|
||||
struct msg_rpc_batch {
|
||||
int type;
|
||||
int service;
|
||||
const char *tag;
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
struct msg_log {
|
||||
int type;
|
||||
const char *fmt;
|
||||
|
|
|
@ -962,7 +962,8 @@ static int process_kmsg(struct msg_base *umsg)
|
|||
break;
|
||||
}
|
||||
|
||||
case MESSAGE_TYPE_RPC_SEND: {
|
||||
case MESSAGE_TYPE_RPC_SEND:
|
||||
case MESSAGE_TYPE_RPC_BATCH: {
|
||||
struct msg_rpc_send *msg = (struct msg_rpc_send *)umsg;
|
||||
|
||||
if(!send_rpc_request(msg->service, msg->tag, msg->args)) {
|
||||
|
@ -971,7 +972,8 @@ static int process_kmsg(struct msg_base *umsg)
|
|||
return 0; // restart session
|
||||
}
|
||||
|
||||
user_kernel_state = USER_KERNEL_WAIT_RPC;
|
||||
if(msg->type == MESSAGE_TYPE_RPC_SEND)
|
||||
user_kernel_state = USER_KERNEL_WAIT_RPC;
|
||||
mailbox_acknowledge();
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue