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([
|
attributes = OrderedDict([
|
||||||
("__name__", TStr()),
|
("__name__", TStr()),
|
||||||
("__file__", TStr()),
|
("__file__", TStr()),
|
||||||
("__line__", TInt(types.TValue(32))),
|
("__line__", TInt32()),
|
||||||
("__col__", TInt(types.TValue(32))),
|
("__col__", TInt32()),
|
||||||
("__func__", TStr()),
|
("__func__", TStr()),
|
||||||
("__message__", TStr()),
|
("__message__", TStr()),
|
||||||
("__param0__", TInt(types.TValue(64))),
|
("__param0__", TInt64()),
|
||||||
("__param1__", TInt(types.TValue(64))),
|
("__param1__", TInt64()),
|
||||||
("__param2__", TInt(types.TValue(64))),
|
("__param2__", TInt64()),
|
||||||
])
|
])
|
||||||
|
|
||||||
def __init__(self, name="Exception", id=0):
|
def __init__(self, name="Exception", id=0):
|
||||||
|
@ -191,6 +191,12 @@ def is_int(typ, width=None):
|
||||||
else:
|
else:
|
||||||
return types.is_mono(typ, "int")
|
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):
|
def get_int_width(typ):
|
||||||
if is_int(typ):
|
if is_int(typ):
|
||||||
return types.get_value(typ.find()["width"])
|
return types.get_value(typ.find()["width"])
|
||||||
|
|
|
@ -81,8 +81,14 @@ class Target:
|
||||||
print(function.as_entity(type_printer), file=sys.stderr)
|
print(function.as_entity(type_printer), file=sys.stderr)
|
||||||
|
|
||||||
llmod = module.build_llvm_ir(self)
|
llmod = module.build_llvm_ir(self)
|
||||||
|
|
||||||
|
try:
|
||||||
llparsedmod = llvm.parse_assembly(str(llmod))
|
llparsedmod = llvm.parse_assembly(str(llmod))
|
||||||
llparsedmod.verify()
|
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"):
|
if os.getenv("ARTIQ_DUMP_LLVM"):
|
||||||
print("====== LLVM IR DUMP ======", file=sys.stderr)
|
print("====== LLVM IR DUMP ======", file=sys.stderr)
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
into LLVM intermediate representation.
|
into LLVM intermediate representation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os, re
|
import os, re, types as pytypes
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from pythonparser import ast, diagnostic
|
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 ...language import core as language_core
|
||||||
from .. import types, builtins, ir
|
from .. import types, builtins, ir
|
||||||
|
|
||||||
|
@ -418,11 +418,21 @@ class LLVMIRGenerator:
|
||||||
return self.llmodule
|
return self.llmodule
|
||||||
|
|
||||||
def emit_attribute_writeback(self):
|
def emit_attribute_writeback(self):
|
||||||
|
llobjects = []
|
||||||
shadow_memory_dim = defaultdict(lambda: 0)
|
shadow_memory_dim = defaultdict(lambda: 0)
|
||||||
|
|
||||||
for obj_id in self.object_map:
|
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)
|
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]
|
_, typ = self.type_map[obj_ref]
|
||||||
else:
|
else:
|
||||||
typ, _ = self.type_map[type(obj_ref)]
|
typ, _ = self.type_map[type(obj_ref)]
|
||||||
|
@ -430,14 +440,18 @@ class LLVMIRGenerator:
|
||||||
if shadow_memory_dim[typ] <= obj_id:
|
if shadow_memory_dim[typ] <= obj_id:
|
||||||
shadow_memory_dim[typ] = obj_id + 1
|
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 = 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 = []
|
lldescs = []
|
||||||
for typ in shadow_memory_dim:
|
for typ in shadow_memory_dim:
|
||||||
if "__objectid__" not in typ.attributes:
|
if "__objectid__" not in typ.attributes:
|
||||||
continue
|
continue
|
||||||
assert list(typ.attributes.keys())[0] == "__objectid__"
|
|
||||||
|
|
||||||
if types.is_constructor(typ):
|
if types.is_constructor(typ):
|
||||||
type_name = "class.{}".format(typ.name)
|
type_name = "class.{}".format(typ.name)
|
||||||
|
@ -455,44 +469,72 @@ class LLVMIRGenerator:
|
||||||
llshadow.type = llshadowty.as_pointer()
|
llshadow.type = llshadowty.as_pointer()
|
||||||
llshadow.initializer = ll.Constant(llshadowty, None)
|
llshadow.initializer = ll.Constant(llshadowty, None)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
def rpc_tag_error(typ):
|
def rpc_tag_error(typ):
|
||||||
print(typ)
|
print(typ)
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
rpcattrary = list(typ.attributes.keys())[1:]
|
rpctag = b"Os"
|
||||||
llrpcattraryty = ll.ArrayType(llptr, len(rpcattrary) + 1)
|
if not (types.is_function(typ) or types.is_method(typ)):
|
||||||
llrpcattrary = list(map(lambda attr: self.llstr_of_str(attr), rpcattrary))
|
rpctag += self._rpc_tag(typ, error_handler=rpc_tag_error)
|
||||||
|
else:
|
||||||
llrpcattrs = ll.GlobalVariable(self.llmodule, llrpcattraryty,
|
rpctag += b""
|
||||||
name="shadow.attrs.{}".format(type_name))
|
rpctag += b":n\x00"
|
||||||
llrpcattrs.initializer = ll.Constant(llrpcattraryty,
|
|
||||||
llrpcattrary + [ll.Constant(llptr, None)])
|
|
||||||
llrpcattrs.linkage = 'internal'
|
|
||||||
|
|
||||||
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)
|
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,
|
lldesc = ll.GlobalVariable(self.llmodule, lldescty,
|
||||||
name="shadow.desc.{}".format(type_name))
|
name="shadow.desc.{}".format(type_name))
|
||||||
lldesc.initializer = ll.Constant(lldescty, [
|
lldesc.initializer = ll.Constant(lldescty, [
|
||||||
llrpcattrs.bitcast(llptr.as_pointer()),
|
llrpcattrary.bitcast(llrpcattrty.as_pointer().as_pointer()),
|
||||||
llrpctag,
|
|
||||||
ll.Constant(lli32, shadow_memory_dim[typ]),
|
ll.Constant(lli32, shadow_memory_dim[typ]),
|
||||||
llshadow.bitcast(llptr)])
|
llshadow.bitcast(llptr)
|
||||||
|
])
|
||||||
|
lldesc.global_constant = True
|
||||||
lldesc.linkage = 'internal'
|
lldesc.linkage = 'internal'
|
||||||
lldescs.append(lldesc)
|
lldescs.append(lldesc)
|
||||||
|
|
||||||
llglobaldescty = ll.ArrayType(lldescty.as_pointer(), len(lldescs) + 1)
|
llglobaldescty = ll.ArrayType(lldescty.as_pointer(), len(lldescs) + 1)
|
||||||
llglobaldesc = ll.GlobalVariable(self.llmodule, llglobaldescty,
|
llglobaldesc = ll.GlobalVariable(self.llmodule, llglobaldescty, name="shadow")
|
||||||
name="shadow.descs")
|
|
||||||
llglobaldesc.initializer = ll.Constant(llglobaldescty,
|
llglobaldesc.initializer = ll.Constant(llglobaldescty,
|
||||||
lldescs + [ll.Constant(lldescty.as_pointer(), None)])
|
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):
|
def process_function(self, func):
|
||||||
try:
|
try:
|
||||||
|
@ -661,10 +703,10 @@ class LLVMIRGenerator:
|
||||||
llidptr = self.llbuilder.gep(self.map(insn.object()),
|
llidptr = self.llbuilder.gep(self.map(insn.object()),
|
||||||
[self.llindex(0), self.llindex(0)])
|
[self.llindex(0), self.llindex(0)])
|
||||||
llid = self.llbuilder.load(llidptr, name="shadow.id")
|
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(
|
llshadowpos = self.llbuilder.add(
|
||||||
self.llbuilder.mul(llid, llattrcount),
|
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):
|
if types.is_constructor(object_type):
|
||||||
shadowname = "shadow.class.{}".format(object_type.name)
|
shadowname = "shadow.class.{}".format(object_type.name)
|
||||||
|
|
|
@ -435,7 +435,11 @@ class CommGeneric:
|
||||||
|
|
||||||
def _serve_rpc(self, object_map):
|
def _serve_rpc(self, object_map):
|
||||||
service_id = self._read_int32()
|
service_id = self._read_int32()
|
||||||
|
if service_id == 0:
|
||||||
|
service = lambda obj, attr, value: setattr(obj, attr, value)
|
||||||
|
else:
|
||||||
service = object_map.retrieve(service_id)
|
service = object_map.retrieve(service_id)
|
||||||
|
|
||||||
arguments = self._receive_rpc_args(object_map, service.__defaults__)
|
arguments = self._receive_rpc_args(object_map, service.__defaults__)
|
||||||
return_tags = self._read_bytes()
|
return_tags = self._read_bytes()
|
||||||
logger.debug("rpc service: [%d]%r %r -> %s", service_id, service, arguments, return_tags)
|
logger.debug("rpc service: [%d]%r %r -> %s", service_id, service, arguments, return_tags)
|
||||||
|
@ -444,6 +448,7 @@ class CommGeneric:
|
||||||
result = service(*arguments)
|
result = service(*arguments)
|
||||||
logger.debug("rpc service: %d %r == %r", service_id, arguments, result)
|
logger.debug("rpc service: %d %r == %r", service_id, arguments, result)
|
||||||
|
|
||||||
|
if service_id != 0:
|
||||||
self._write_header(_H2DMsgType.RPC_REPLY)
|
self._write_header(_H2DMsgType.RPC_REPLY)
|
||||||
self._write_bytes(return_tags)
|
self._write_bytes(return_tags)
|
||||||
self._send_rpc_value(bytearray(return_tags), result, result, service)
|
self._send_rpc_value(bytearray(return_tags), result, result, service)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
double round(double x);
|
double round(double x);
|
||||||
|
|
||||||
void ksupport_abort(void);
|
void ksupport_abort(void);
|
||||||
|
static void attribute_writeback(void *, void *);
|
||||||
|
|
||||||
int64_t now;
|
int64_t now;
|
||||||
|
|
||||||
|
@ -249,14 +250,22 @@ int main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(request->run_kernel) {
|
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);
|
mailbox_send_and_wait(&load_reply);
|
||||||
|
|
||||||
now = now_init();
|
now = now_init();
|
||||||
kernel_init();
|
kernel_run();
|
||||||
now_save(now);
|
now_save(now);
|
||||||
|
|
||||||
|
attribute_writeback(shadow, objects);
|
||||||
|
|
||||||
struct msg_base finished_reply;
|
struct msg_base finished_reply;
|
||||||
finished_reply.type = MESSAGE_TYPE_FINISHED;
|
finished_reply.type = MESSAGE_TYPE_FINISHED;
|
||||||
mailbox_send_and_wait(&finished_reply);
|
mailbox_send_and_wait(&finished_reply);
|
||||||
|
@ -357,7 +366,10 @@ void send_rpc(int service, const char *tag, ...)
|
||||||
{
|
{
|
||||||
struct msg_rpc_send request;
|
struct msg_rpc_send request;
|
||||||
|
|
||||||
|
if(service != 0)
|
||||||
request.type = MESSAGE_TYPE_RPC_SEND;
|
request.type = MESSAGE_TYPE_RPC_SEND;
|
||||||
|
else
|
||||||
|
request.type = MESSAGE_TYPE_RPC_BATCH;
|
||||||
request.service = service;
|
request.service = service;
|
||||||
request.tag = tag;
|
request.tag = tag;
|
||||||
va_start(request.args, 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, ...)
|
void lognonl(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
struct msg_log request;
|
struct msg_log request;
|
||||||
|
|
|
@ -17,6 +17,7 @@ enum {
|
||||||
MESSAGE_TYPE_RPC_SEND,
|
MESSAGE_TYPE_RPC_SEND,
|
||||||
MESSAGE_TYPE_RPC_RECV_REQUEST,
|
MESSAGE_TYPE_RPC_RECV_REQUEST,
|
||||||
MESSAGE_TYPE_RPC_RECV_REPLY,
|
MESSAGE_TYPE_RPC_RECV_REPLY,
|
||||||
|
MESSAGE_TYPE_RPC_BATCH,
|
||||||
MESSAGE_TYPE_LOG,
|
MESSAGE_TYPE_LOG,
|
||||||
|
|
||||||
MESSAGE_TYPE_BRG_READY,
|
MESSAGE_TYPE_BRG_READY,
|
||||||
|
@ -97,6 +98,13 @@ struct msg_rpc_recv_reply {
|
||||||
struct artiq_exception *exception;
|
struct artiq_exception *exception;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct msg_rpc_batch {
|
||||||
|
int type;
|
||||||
|
int service;
|
||||||
|
const char *tag;
|
||||||
|
void *ptr;
|
||||||
|
};
|
||||||
|
|
||||||
struct msg_log {
|
struct msg_log {
|
||||||
int type;
|
int type;
|
||||||
const char *fmt;
|
const char *fmt;
|
||||||
|
|
|
@ -962,7 +962,8 @@ static int process_kmsg(struct msg_base *umsg)
|
||||||
break;
|
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;
|
struct msg_rpc_send *msg = (struct msg_rpc_send *)umsg;
|
||||||
|
|
||||||
if(!send_rpc_request(msg->service, msg->tag, msg->args)) {
|
if(!send_rpc_request(msg->service, msg->tag, msg->args)) {
|
||||||
|
@ -971,6 +972,7 @@ static int process_kmsg(struct msg_base *umsg)
|
||||||
return 0; // restart session
|
return 0; // restart session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(msg->type == MESSAGE_TYPE_RPC_SEND)
|
||||||
user_kernel_state = USER_KERNEL_WAIT_RPC;
|
user_kernel_state = USER_KERNEL_WAIT_RPC;
|
||||||
mailbox_acknowledge();
|
mailbox_acknowledge();
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue