Permalink
Browse files

AOT compiler: added support for blocks

  • Loading branch information...
1 parent 57d8085 commit 2c54dbd264ca8f9dd0f2479308a7b5fec74b80dc @lrz lrz committed Jul 1, 2009
Showing with 112 additions and 80 deletions.
  1. +48 −27 compiler.cpp
  2. +4 −1 compiler.h
  3. +50 −43 vm.cpp
  4. +9 −7 vm.h
  5. +1 −2 vm_eval.c
View
@@ -551,6 +551,15 @@ RoxorCompiler::compile_prepare_method(Value *classVal, Value *sel,
params.end(), "", bb);
}
+inline Value *
+RoxorCompiler::compile_arity(rb_vm_arity_t &arity)
+{
+ uint64_t v;
+ assert(sizeof(uint64_t) == sizeof(rb_vm_arity_t));
+ memcpy(&v, &arity, sizeof(rb_vm_arity_t));
+ return ConstantInt::get(Type::Int64Ty, v);
+}
+
void
RoxorAOTCompiler::compile_prepare_method(Value *classVal, Value *sel,
Function *new_function, rb_vm_arity_t &arity, NODE *body)
@@ -575,11 +584,7 @@ RoxorAOTCompiler::compile_prepare_method(Value *classVal, Value *sel,
GET_CORE()->compile(new_function);
params.push_back(new BitCastInst(new_function, PtrTy, "", bb));
- uint64_t v;
- assert(sizeof(uint64_t) == sizeof(rb_vm_arity_t));
- memcpy(&v, &arity, sizeof(rb_vm_arity_t));
- params.push_back(ConstantInt::get(Type::Int64Ty, v));
-
+ params.push_back(compile_arity(arity));
params.push_back(ConstantInt::get(Type::Int32Ty, rb_vm_node_flags(body)));
CallInst::Create(prepareMethodFunc, params.begin(),
@@ -797,6 +802,21 @@ RoxorCompiler::compile_multiple_assignment(NODE *node, Value *val)
}
Value *
+RoxorCompiler::compile_prepare_block_args(Function *func, int *flags)
+{
+ return compile_const_pointer(func);
+}
+
+Value *
+RoxorAOTCompiler::compile_prepare_block_args(Function *func, int *flags)
+{
+ *flags |= VM_BLOCK_AOT;
+ // Force compilation (no stub).
+ GET_CORE()->compile(func);
+ return new BitCastInst(func, PtrTy, "", bb);
+}
+
+Value *
RoxorCompiler::compile_block_create(NODE *node)
{
if (node != NULL) {
@@ -815,14 +835,16 @@ RoxorCompiler::compile_block_create(NODE *node)
assert(current_block_func != NULL && current_block_node != NULL);
if (prepareBlockFunc == NULL) {
- // void *rb_vm_prepare_block(Function *func, NODE *node, VALUE self,
- // rb_vm_var_uses **parent_var_uses,
- // rb_vm_block_t *parent_block,
- // int dvars_size, ...);
+ // void *rb_vm_prepare_block(Function *func, int flags, VALUE self,
+ // rb_vm_arity_t arity,
+ // rb_vm_var_uses **parent_var_uses,
+ // rb_vm_block_t *parent_block,
+ // int dvars_size, ...);
std::vector<const Type *> types;
types.push_back(PtrTy);
- types.push_back(PtrTy);
+ types.push_back(Type::Int32Ty);
types.push_back(RubyObjTy);
+ types.push_back(Type::Int64Ty);
types.push_back(PtrPtrTy);
types.push_back(PtrTy);
types.push_back(Type::Int32Ty);
@@ -832,22 +854,20 @@ RoxorCompiler::compile_block_create(NODE *node)
}
std::vector<Value *> params;
- params.push_back(compile_const_pointer(current_block_func));
- params.push_back(compile_const_pointer(current_block_node));
- params.push_back(current_self);
- if (current_var_uses == NULL) {
- // there is no local variables in this scope
- params.push_back(compile_const_pointer_to_pointer(NULL));
- }
- else {
- params.push_back(current_var_uses);
- }
- if (running_block == NULL) {
- params.push_back(compile_const_pointer(NULL));
- }
- else {
- params.push_back(running_block);
+ int flags = 0;
+ params.push_back(compile_prepare_block_args(current_block_func, &flags));
+ if (nd_type(current_block_node) == NODE_SCOPE
+ && current_block_node->nd_body == NULL) {
+ flags |= VM_BLOCK_EMPTY;
}
+ params.push_back(ConstantInt::get(Type::Int32Ty, flags));
+ params.push_back(current_self);
+ rb_vm_arity_t arity = rb_vm_node_arity(current_block_node);
+ params.push_back(compile_arity(arity));
+ params.push_back(current_var_uses == NULL
+ ? compile_const_pointer_to_pointer(NULL) : current_var_uses);
+ params.push_back(running_block == NULL
+ ? compile_const_pointer(NULL) : running_block);
// Dvars.
params.push_back(ConstantInt::get(Type::Int32Ty, (int)dvars.size()));
@@ -3385,7 +3405,8 @@ RoxorCompiler::compile_node(NODE *node)
}
else {
blockVal = block_given
- ? compile_block_create() : compile_const_pointer(NULL);
+ ? compile_block_create(NULL)
+ : compile_const_pointer(NULL);
}
params[3] = blockVal;
@@ -4172,7 +4193,7 @@ RoxorCompiler::compile_node(NODE *node)
params.push_back(compile_mcache(selEach, false));
params.push_back(compile_node(node->nd_iter));
params.push_back(compile_sel(selEach));
- params.push_back(compile_block_create());
+ params.push_back(compile_block_create(NULL));
params.push_back(ConstantInt::get(Type::Int8Ty, 0));
params.push_back(ConstantInt::get(Type::Int32Ty, 0));
View
@@ -202,7 +202,8 @@ class RoxorCompiler {
Value *compile_when_splat(Value *comparedToVal, Value *splatVal);
Value *compile_fast_eqq_call(Value *selfVal, Value *comparedToVal);
Value *compile_attribute_assign(NODE *node, Value *extra_val);
- Value *compile_block_create(NODE *node=NULL);
+ virtual Value *compile_prepare_block_args(Function *func, int *flags);
+ Value *compile_block_create(NODE *node);
Value *compile_binding(void);
Value *compile_optimized_dispatch_call(SEL sel, int argc,
std::vector<Value *> &params);
@@ -230,6 +231,7 @@ class RoxorCompiler {
}
virtual Value *compile_id(ID id);
GlobalVariable *compile_const_global_string(const char *str);
+ Value *compile_arity(rb_vm_arity_t &arity);
void compile_landing_pad_header(void);
void compile_landing_pad_footer(void);
@@ -301,6 +303,7 @@ class RoxorAOTCompiler : public RoxorCompiler {
Instruction *compile_sel(SEL sel, bool add_to_bb=true);
void compile_prepare_method(Value *classVal, Value *sel,
Function *new_function, rb_vm_arity_t &arity, NODE *body);
+ Value *compile_prepare_block_args(Function *func, int *flags);
Value *compile_nsobject(void);
Value *compile_id(ID id);
View
93 vm.cpp
@@ -242,15 +242,13 @@ RoxorVM::RoxorVM(void)
parse_in_eval = false;
}
-static inline NODE *
-block_cache_key(NODE *node)
+static inline void *
+block_cache_key(const rb_vm_block_t *b)
{
- if (nd_type(node) == NODE_IFUNC) {
- // In this case, node is dynamic but fortunately u1.node is always
- // unique (it contains the IMP)
- return node->u1.node;
+ if ((b->flags & VM_BLOCK_IFUNC) == VM_BLOCK_IFUNC) {
+ return (void *)b->imp;
}
- return node;
+ return (void *)b->userdata;
}
RoxorVM::RoxorVM(const RoxorVM &vm)
@@ -261,6 +259,7 @@ RoxorVM::RoxorVM(const RoxorVM &vm)
std::vector<rb_vm_block_t *> &vm_blocks =
const_cast<RoxorVM &>(vm).current_blocks;
+
for (std::vector<rb_vm_block_t *>::iterator i = vm_blocks.begin();
(i + 1) != vm_blocks.end();
++i) {
@@ -280,13 +279,11 @@ RoxorVM::RoxorVM(const RoxorVM &vm)
memcpy(b, orig, block_size);
GC_WB(&b->self, orig->self);
- GC_WB(&b->node, orig->node);
GC_WB(&b->locals, orig->locals);
GC_WB(&b->parent_block, orig->parent_block); // XXX not sure
#endif
rb_objc_retain(b);
- NODE *key = block_cache_key(orig->node);
- blocks[key] = b;
+ blocks[block_cache_key(orig)] = b;
}
current_blocks.push_back(b);
}
@@ -2913,9 +2910,9 @@ rb_vm_dup_active_block(rb_vm_block_t *src_b)
}
rb_vm_block_t *
-RoxorVM::uncache_or_create_block(NODE *key, bool *cached, int dvars_size)
+RoxorVM::uncache_or_create_block(void *key, bool *cached, int dvars_size)
{
- std::map<NODE *, rb_vm_block_t *>::iterator iter = blocks.find(key);
+ std::map<void *, rb_vm_block_t *>::iterator iter = blocks.find(key);
rb_vm_block_t *b;
@@ -2925,9 +2922,11 @@ RoxorVM::uncache_or_create_block(NODE *key, bool *cached, int dvars_size)
if (iter != blocks.end()) {
rb_objc_release(iter->second);
}
+
b = (rb_vm_block_t *)xmalloc(sizeof(rb_vm_block_t)
+ (sizeof(VALUE *) * dvars_size));
rb_objc_retain(b);
+
blocks[key] = b;
*cached = false;
}
@@ -2941,40 +2940,44 @@ RoxorVM::uncache_or_create_block(NODE *key, bool *cached, int dvars_size)
extern "C"
rb_vm_block_t *
-rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self,
+rb_vm_prepare_block(void *function, int flags, VALUE self, rb_vm_arity_t arity,
rb_vm_var_uses **parent_var_uses, rb_vm_block_t *parent_block,
int dvars_size, ...)
{
- NODE *cache_key = block_cache_key(node);
+ assert(function != NULL);
bool cached = false;
- rb_vm_block_t *b = GET_VM()->uncache_or_create_block(cache_key, &cached,
+ rb_vm_block_t *b = GET_VM()->uncache_or_create_block(function, &cached,
dvars_size);
if (!cached) {
- if (nd_type(node) == NODE_IFUNC) {
- assert(llvm_function == NULL);
- b->imp = (IMP)node->u1.node;
- memset(&b->arity, 0, sizeof(rb_vm_arity_t)); // not used
+ if ((flags & VM_BLOCK_IFUNC) == VM_BLOCK_IFUNC) {
+ b->imp = (IMP)function;
}
else {
- assert(llvm_function != NULL);
- GET_CORE()->lock();
- b->imp = GET_CORE()->compile((Function *)llvm_function);
- GET_CORE()->unlock();
- b->arity = rb_vm_node_arity(node);
+ if ((flags & VM_BLOCK_AOT) == VM_BLOCK_AOT) {
+ flags ^= VM_BLOCK_AOT;
+ b->imp = (IMP)function;
+ }
+ else {
+ GET_CORE()->lock();
+ b->imp = GET_CORE()->compile((Function *)function);
+ GET_CORE()->unlock();
+ }
+ b->userdata = (VALUE)function;
}
- b->flags = 0;
+ b->arity = arity;
+ b->flags = flags;
b->dvars_size = dvars_size;
b->parent_var_uses = NULL;
b->parent_block = NULL;
}
else {
assert(b->dvars_size == dvars_size);
+ assert((b->flags & flags) == flags);
}
b->self = self;
- b->node = node;
b->parent_var_uses = parent_var_uses;
GC_WB(&b->parent_block, parent_block);
@@ -3006,6 +3009,17 @@ rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self,
}
extern "C"
+rb_vm_block_t *
+rb_vm_create_block(IMP imp, VALUE self, VALUE userdata)
+{
+ rb_vm_block_t *b = rb_vm_prepare_block((void *)imp, VM_BLOCK_IFUNC, self,
+ rb_vm_arity(0), // not used
+ NULL, NULL, 0, 0);
+ GC_WB(&b->userdata, userdata);
+ return b;
+}
+
+extern "C"
void*
rb_gc_read_weak_ref(void **referrer);
@@ -3383,7 +3397,6 @@ rb_vm_create_block_from_method(rb_vm_method_t *method)
rb_vm_block_t *b = (rb_vm_block_t *)xmalloc(sizeof(rb_vm_block_t));
GC_WB(&b->self, method->recv);
- b->node = NULL;
b->arity = method->node == NULL
? rb_vm_arity(method->arity) : method->node->arity;
b->imp = (IMP)method;
@@ -3424,23 +3437,17 @@ rb_vm_create_block_calling_sel(SEL sel)
static inline VALUE
rb_vm_block_eval0(rb_vm_block_t *b, VALUE self, int argc, const VALUE *argv)
{
- if (b->node != NULL) {
- if (nd_type(b->node) == NODE_IFUNC) {
- // Special case for blocks passed with rb_objc_block_call(), to
- // preserve API compatibility.
- VALUE data = (VALUE)b->node->u2.node;
-
- VALUE (*pimp)(VALUE, VALUE, int, const VALUE *) =
- (VALUE (*)(VALUE, VALUE, int, const VALUE *))b->imp;
+ if ((b->flags & VM_BLOCK_IFUNC) == VM_BLOCK_IFUNC) {
+ // Special case for blocks passed with rb_objc_block_call(), to
+ // preserve API compatibility.
+ VALUE (*pimp)(VALUE, VALUE, int, const VALUE *) =
+ (VALUE (*)(VALUE, VALUE, int, const VALUE *))b->imp;
- return (*pimp)(argc == 0 ? Qnil : argv[0], data, argc, argv);
- }
- else if (nd_type(b->node) == NODE_SCOPE) {
- if (b->node->nd_body == NULL) {
- // Trying to call an empty block!
- return Qnil;
- }
- }
+ return (*pimp)(argc == 0 ? Qnil : argv[0], b->userdata, argc, argv);
+ }
+ else if ((b->flags & VM_BLOCK_EMPTY) == VM_BLOCK_EMPTY) {
+ // Trying to call an empty block!
+ return Qnil;
}
rb_vm_arity_t arity = b->arity;
View
16 vm.h
@@ -30,10 +30,15 @@ typedef struct rb_vm_local {
#define VM_BLOCK_LAMBDA 0x0002 // block is a lambda
#define VM_BLOCK_ACTIVE 0x0004 // block is active (being executed)
#define VM_BLOCK_METHOD 0x0008 // block is created from Method
+#define VM_BLOCK_IFUNC 0x0010 // block is created from rb_vm_create_block()
+#define VM_BLOCK_EMPTY 0x0012 // block has an empty body
+
+#define VM_BLOCK_AOT 0x1000 // block is created by the AOT compiler (temporary)
typedef struct rb_vm_block {
VALUE self;
- NODE *node;
+ VALUE userdata; // if VM_BLOCK_IFUNC, contains the user data, otherwise
+ // contains the key used in the blocks cache.
rb_vm_arity_t arity;
IMP imp;
int flags;
@@ -336,10 +341,7 @@ rb_proc_get_block(VALUE proc)
}
void rb_vm_add_block_lvar_use(rb_vm_block_t *block);
-rb_vm_block_t *rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self,
- struct rb_vm_var_uses **parent_lvar_uses,
- rb_vm_block_t *parent_block,
- int dvars_size, ...);
+rb_vm_block_t *rb_vm_create_block(IMP imp, VALUE self, VALUE userdata);
rb_vm_block_t *rb_vm_current_block(void);
rb_vm_block_t *rb_vm_first_block(void);
bool rb_vm_block_saved(void);
@@ -730,7 +732,7 @@ class RoxorVM {
private:
// Cache to avoid allocating the same block twice.
- std::map<NODE *, rb_vm_block_t *> blocks;
+ std::map<void *, rb_vm_block_t *> blocks;
// Keeps track of the current VM state (blocks, exceptions, bindings).
std::vector<rb_vm_block_t *> current_blocks;
@@ -804,7 +806,7 @@ class RoxorVM {
return b;
}
- rb_vm_block_t *uncache_or_create_block(NODE *key, bool *cached,
+ rb_vm_block_t *uncache_or_create_block(void *key, bool *cached,
int dvars_size);
rb_vm_binding_t *current_binding(void) {
View
@@ -281,8 +281,7 @@ VALUE
rb_objc_block_call(VALUE obj, SEL sel, void *cache, int argc, VALUE *argv,
VALUE (*bl_proc) (ANYARGS), VALUE data2)
{
- NODE *node = NEW_IFUNC(bl_proc, data2);
- rb_vm_block_t *b = rb_vm_prepare_block(NULL, node, obj, NULL, NULL, 0, 0);
+ rb_vm_block_t *b = rb_vm_create_block((IMP)bl_proc, obj, data2);
if (cache == NULL) {
cache = rb_vm_get_call_cache(sel);
}

0 comments on commit 2c54dbd

Please sign in to comment.