Implement selective attribute writeback using shadow memory.

This commit is contained in:
whitequark 2016-01-02 22:51:04 +08:00
parent 2e33084a5f
commit 38a99fde52
7 changed files with 173 additions and 48 deletions

View File

@ -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"])

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;