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([
("__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"])

View File

@ -81,8 +81,14 @@ class Target:
print(function.as_entity(type_printer), file=sys.stderr)
llmod = module.build_llvm_ir(self)
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)

View File

@ -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 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):
print(typ)
assert False
rpcattrary = list(typ.attributes.keys())[1:]
llrpcattraryty = ll.ArrayType(llptr, len(rpcattrary) + 1)
llrpcattrary = list(map(lambda attr: self.llstr_of_str(attr), rpcattrary))
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""
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"
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)
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)

View File

@ -435,7 +435,11 @@ class CommGeneric:
def _serve_rpc(self, object_map):
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)
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,6 +448,7 @@ class CommGeneric:
result = service(*arguments)
logger.debug("rpc service: %d %r == %r", service_id, arguments, result)
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)

View File

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

View File

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

View File

@ -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,6 +972,7 @@ static int process_kmsg(struct msg_base *umsg)
return 0; // restart session
}
if(msg->type == MESSAGE_TYPE_RPC_SEND)
user_kernel_state = USER_KERNEL_WAIT_RPC;
mailbox_acknowledge();
break;