[macruby-changes] [1402] MacRuby/branches/experimental
source_changes at macosforge.org
source_changes at macosforge.org
Wed Apr 8 22:07:07 PDT 2009
Revision: 1402
http://trac.macosforge.org/projects/ruby/changeset/1402
Author: lsansonetti at apple.com
Date: 2009-04-08 22:07:07 -0700 (Wed, 08 Apr 2009)
Log Message:
-----------
experimental ultra-lazy JIT (disabled for now, work in progress)
Modified Paths:
--------------
MacRuby/branches/experimental/class.c
MacRuby/branches/experimental/roxor.cpp
MacRuby/branches/experimental/roxor.h
Modified: MacRuby/branches/experimental/class.c
===================================================================
--- MacRuby/branches/experimental/class.c 2009-04-08 05:06:27 UTC (rev 1401)
+++ MacRuby/branches/experimental/class.c 2009-04-09 05:07:07 UTC (rev 1402)
@@ -572,28 +572,7 @@
DLOG("INCM", "%s <- %s", class_getName((Class)klass), class_getName((Class)module));
if (add_methods) {
- Method *methods;
- unsigned int i, methods_count;
-
- methods = class_copyMethodList((Class)module, &methods_count);
- if (methods != NULL) {
- for (i = 0; i < methods_count; i++) {
- Method method = methods[i], method2;
- DLOG("DEFI", "-[%s %s]", class_getName((Class)klass), (char *)method_getName(method));
-
- method2 = class_getInstanceMethod((Class)klass, method_getName(method));
- if (method2 != NULL && method2 != class_getInstanceMethod((Class)RCLASS_SUPER(klass), method_getName(method))) {
- method_setImplementation(method2, method_getImplementation(method));
- }
- else {
- assert(class_addMethod((Class)klass,
- method_getName(method),
- method_getImplementation(method),
- method_getTypeEncoding(method)));
- }
- }
- free(methods);
- }
+ rb_vm_copy_methods((Class)module, (Class)klass);
}
}
Modified: MacRuby/branches/experimental/roxor.cpp
===================================================================
--- MacRuby/branches/experimental/roxor.cpp 2009-04-08 05:06:27 UTC (rev 1401)
+++ MacRuby/branches/experimental/roxor.cpp 2009-04-09 05:07:07 UTC (rev 1402)
@@ -3,6 +3,7 @@
#define ROXOR_COMPILER_DEBUG 0
#define ROXOR_VM_DEBUG 0
#define ROXOR_DUMP_IR_BEFORE_EXIT 0
+#define ROXOR_ULTRA_LAZY_JIT 0
#include <llvm/Module.h>
#include <llvm/DerivedTypes.h>
@@ -387,6 +388,11 @@
int nested;
} rb_vm_catch_t;
+typedef struct {
+ Function *func;
+ NODE *node;
+} rb_vm_method_source_t;
+
class RoxorVM
{
private:
@@ -427,60 +433,25 @@
std::map<VALUE, rb_vm_catch_t *> catch_jmp_bufs;
std::vector<jmp_buf *> return_from_block_jmp_bufs;
+#if ROXOR_ULTRA_LAZY_JIT
+ std::map<Class, std::map<SEL, rb_vm_method_source_t *> *>
+ method_sources;
+#endif
+
RoxorVM(void);
- ExecutionEngine *execution_engine(void) { return ee; }
-
IMP compile(Function *func);
- bool symbolize_call_address(void *addr, void **startp, unsigned long *ln,
- char *name, size_t name_len) {
- void *start = NULL;
+ bool symbolize_call_address(void *addr, void **startp,
+ unsigned long *ln, char *name, size_t name_len);
- RoxorFunction *f = jmm->find_function((unsigned char *)addr);
- if (f != NULL) {
- if (f->imp == NULL) {
- f->imp = ee->getPointerToFunctionOrStub(f->f);
- }
- start = f->imp;
- }
- else {
- if (!rb_objc_symbolize_address(addr, &start, NULL, 0)) {
- return false;
- }
- }
-
- assert(start != NULL);
- if (startp != NULL) {
- *startp = start;
- }
-
- if (name != NULL || ln != NULL) {
- std::map<IMP, struct RoxorFunctionIMP *>::iterator iter =
- ruby_imps.find((IMP)start);
- if (iter == ruby_imps.end()) {
- // TODO symbolize objc selectors
- return false;
- }
-
- struct RoxorFunctionIMP *fi = iter->second;
- if (ln != NULL) {
- *ln = nd_line(fi->node);
- }
- if (name != NULL) {
- strncpy(name, sel_getName(fi->sel), name_len);
- }
- }
-
- return true;
- }
-
bool is_running(void) { return running; }
void set_running(bool flag) { running = flag; }
struct mcache *method_cache_get(SEL sel, bool super);
NODE *method_node_get(IMP imp);
- void add_method(Class klass, SEL sel, IMP imp, NODE *node, const char *types);
+ void add_method(Class klass, SEL sel, IMP imp, NODE *node,
+ const char *types);
GlobalVariable *redefined_op_gvar(SEL sel, bool create);
bool should_invalidate_inline_op(SEL sel, Class klass);
@@ -2299,12 +2270,57 @@
uint64_t elapsedNano = elapsed * sTimebaseInfo.numer / sTimebaseInfo.denom;
- printf("compilation done, took %lld ns\n", elapsedNano);
+ printf("compilation of LLVM function %p done, took %lld ns\n",
+ func, elapsedNano);
#endif
return imp;
}
+bool
+RoxorVM::symbolize_call_address(void *addr, void **startp, unsigned long *ln,
+ char *name, size_t name_len)
+{
+ void *start = NULL;
+
+ RoxorFunction *f = jmm->find_function((unsigned char *)addr);
+ if (f != NULL) {
+ if (f->imp == NULL) {
+ f->imp = ee->getPointerToFunctionOrStub(f->f);
+ }
+ start = f->imp;
+ }
+ else {
+ if (!rb_objc_symbolize_address(addr, &start, NULL, 0)) {
+ return false;
+ }
+ }
+
+ assert(start != NULL);
+ if (startp != NULL) {
+ *startp = start;
+ }
+
+ if (name != NULL || ln != NULL) {
+ std::map<IMP, struct RoxorFunctionIMP *>::iterator iter =
+ ruby_imps.find((IMP)start);
+ if (iter == ruby_imps.end()) {
+ // TODO symbolize objc selectors
+ return false;
+ }
+
+ struct RoxorFunctionIMP *fi = iter->second;
+ if (ln != NULL) {
+ *ln = nd_line(fi->node);
+ }
+ if (name != NULL) {
+ strncpy(name, sel_getName(fi->sel), name_len);
+ }
+ }
+
+ return true;
+}
+
struct ccache *
RoxorVM::constant_cache_get(ID path)
{
@@ -4637,8 +4653,6 @@
// VM primitives
-#define MAX_ARITY 20
-
extern "C"
bool
rb_vm_running(void)
@@ -4824,6 +4838,10 @@
VALUE
rb_vm_ivar_get(VALUE obj, ID name, int *slot_cache)
{
+#if ROXOR_VM_DEBUG
+ printf("get ivar %p.%s slot %d\n", (void *)obj, rb_id2name(name),
+ slot_cache == NULL ? -1 : *slot_cache);
+#endif
if (slot_cache == NULL || *slot_cache == -1) {
return rb_ivar_get(obj, name);
}
@@ -4837,6 +4855,12 @@
void
rb_vm_ivar_set(VALUE obj, ID name, VALUE val, int *slot_cache)
{
+#if ROXOR_VM_DEBUG
+ printf("set ivar %p.%s slot %d new_val %p\n", (void *)obj,
+ rb_id2name(name),
+ slot_cache == NULL ? -1 : *slot_cache,
+ (void *)val);
+#endif
if (slot_cache == NULL || *slot_cache == -1) {
rb_ivar_set(obj, name, val);
}
@@ -5060,6 +5084,58 @@
return -1;
}
+#if ROXOR_ULTRA_LAZY_JIT
+static bool
+rb_vm_resolve_method(Class klass, SEL sel)
+{
+ //printf("rb_vm_resolve_method %s (%p) %s\n",class_getName(klass),klass,(char*)sel);
+ rb_vm_method_source_t *m = NULL;
+ std::map<SEL, rb_vm_method_source_t *> *dict = NULL;
+
+ while (true) {
+ std::map<Class, std::map<SEL, rb_vm_method_source_t *> *>::iterator
+ iter = GET_VM()->method_sources.find(klass);
+
+ if (iter != GET_VM()->method_sources.end()) {
+ dict = iter->second;
+ std::map<SEL, rb_vm_method_source_t *>::iterator iter2 =
+ dict->find(sel);
+
+ if (iter2 != dict->end()) {
+ m = iter2->second;
+ break;
+ }
+ }
+ klass = class_getSuperclass(klass);
+ if (klass == NULL) {
+ return false;
+ }
+ }
+
+ //printf("LLVM func %p\n",m->func);
+
+ IMP imp = GET_VM()->compile(m->func);
+
+ const int oc_arity = rb_vm_node_arity(m->node).real;
+
+ char *types = (char *)alloca(oc_arity + 4);
+ types[0] = '@';
+ types[1] = '@';
+ types[2] = ':';
+ for (int i = 0; i < oc_arity; i++) {
+ types[3 + i] = '@';
+ }
+ types[3 + oc_arity] = '\0';
+
+ GET_VM()->add_method(klass, sel, imp, m->node, types);
+
+ dict->erase(sel);
+ free(m);
+
+ return true;
+}
+#endif
+
extern "C"
void
rb_vm_prepare_method(Class klass, SEL sel, Function *func, NODE *node)
@@ -5068,12 +5144,153 @@
klass = GET_VM()->current_class;
}
+#if ROXOR_ULTRA_LAZY_JIT
+
+ // Let's keep the LLVM function and JIT it later.
+ std::map<Class, std::map<SEL, rb_vm_method_source_t *> *>::iterator iter =
+ GET_VM()->method_sources.find(klass);
+ std::map<SEL, rb_vm_method_source_t *> *dict;
+
+ if (iter == GET_VM()->method_sources.end()) {
+ dict = new std::map< SEL, rb_vm_method_source_t *>();
+ GET_VM()->method_sources[klass] = dict;
+ }
+ else {
+ dict = iter->second;
+ }
+
+ const rb_vm_arity_t arity = rb_vm_node_arity(node);
+ const char *sel_name = sel_getName(sel);
+ const bool genuine_selector = sel_name[strlen(sel_name) - 1] == ':';
+ bool redefined = false;
+ SEL orig_sel = sel;
+ IMP imp = NULL;
+
+prepare_method:
+
+ if (class_getInstanceMethod(klass, sel) != NULL) {
+ if (imp == NULL) {
+ imp = GET_VM()->compile(func);
+ }
+ rb_vm_define_method(klass, sel, imp, node, true);
+ }
+ else {
+#if ROXOR_VM_DEBUG
+ printf("preparing %c[%s %s] with LLVM func %p node %p\n",
+ class_isMetaClass(klass) ? '+' : '-',
+ class_getName(klass),
+ sel_getName(sel),
+ func,
+ node);
+#endif
+
+ std::map<SEL, rb_vm_method_source_t *>::iterator iter2 =
+ dict->find(sel);
+ rb_vm_method_source_t *m = NULL;
+ if (iter2 == dict->end()) {
+ m = (rb_vm_method_source_t *)malloc(sizeof(rb_vm_method_source_t));
+ dict->insert(std::make_pair(sel, m));
+ }
+ else {
+ m = iter2->second;
+ }
+
+ m->func = func;
+ m->node = node;
+ }
+
+ if (!redefined) {
+ if (!genuine_selector && arity.max != arity.min) {
+ char buf[100];
+ snprintf(buf, sizeof buf, "%s:", sel_name);
+ sel = sel_registerName(buf);
+ redefined = true;
+
+ goto prepare_method;
+ }
+ else if (genuine_selector && arity.min == 0) {
+ char buf[100];
+ strlcpy(buf, sel_name, sizeof buf);
+ buf[strlen(buf) - 1] = 0; // remove the ending ':'
+ sel = sel_registerName(buf);
+ redefined = true;
+
+ goto prepare_method;
+ }
+ }
+
+ if (RCLASS_VERSION(klass) & RCLASS_IS_INCLUDED) {
+ VALUE included_in_classes = rb_attr_get((VALUE)klass,
+ idIncludedInClasses);
+ if (included_in_classes != Qnil) {
+ int i, count = RARRAY_LEN(included_in_classes);
+ for (i = 0; i < count; i++) {
+ VALUE mod = RARRAY_AT(included_in_classes, i);
+ rb_vm_prepare_method((Class)mod, orig_sel, func, node);
+ }
+ }
+ }
+
+#else // !ROXOR_ULTRA_LAZY_JIT
+
IMP imp = GET_VM()->compile(func);
+ rb_vm_define_method(klass, sel, imp, node, false);
- rb_vm_define_method(klass, sel, imp, node, false);
+#endif
}
extern "C"
+void
+rb_vm_copy_methods(Class from_class, Class to_class)
+{
+ Method *methods;
+ unsigned int i, methods_count;
+
+ methods = class_copyMethodList(from_class, &methods_count);
+ if (methods != NULL) {
+ for (i = 0; i < methods_count; i++) {
+ Method method = methods[i];
+
+ class_replaceMethod(to_class,
+ method_getName(method),
+ method_getImplementation(method),
+ method_getTypeEncoding(method));
+ }
+ free(methods);
+ }
+
+#if ROXOR_ULTRA_LAZY_JIT
+ std::map<Class, std::map<SEL, rb_vm_method_source_t *> *>::iterator
+ iter = GET_VM()->method_sources.find(from_class);
+
+ if (iter != GET_VM()->method_sources.end()) {
+ std::map<SEL, rb_vm_method_source_t *> *from_dict = iter->second;
+
+ std::map<Class, std::map<SEL, rb_vm_method_source_t *> *>::iterator
+ iter2 = GET_VM()->method_sources.find(to_class);
+
+ std::map<SEL, rb_vm_method_source_t *> *to_dict;
+ if (iter2 == GET_VM()->method_sources.end()) {
+ to_dict = new std::map< SEL, rb_vm_method_source_t *>();
+ GET_VM()->method_sources[to_class] = to_dict;
+ }
+ else {
+ to_dict = iter2->second;
+ }
+
+ for (std::map<SEL, rb_vm_method_source_t *>::iterator i =
+ from_dict->begin(); i != from_dict->end(); ++i) {
+ rb_vm_method_source_t *m = (rb_vm_method_source_t *)malloc(
+ sizeof(rb_vm_method_source_t));
+ m->func = i->second->func;
+ m->node = i->second->node;
+ to_dict->insert(std::make_pair(i->first, m));
+ }
+ }
+#endif
+}
+
+extern "C"
bool
rb_vm_lookup_method2(Class klass, ID mid, SEL *psel, IMP *pimp, NODE **pnode)
{
@@ -5115,7 +5332,8 @@
extern "C"
void
-rb_vm_define_attr(Class klass, const char *name, bool read, bool write, int noex)
+rb_vm_define_attr(Class klass, const char *name, bool read, bool write,
+ int noex)
{
assert(klass != NULL);
assert(read || write);
@@ -5128,25 +5346,41 @@
if (read) {
Function *f = compiler->compile_read_attr(iname);
+ SEL sel = sel_registerName(name);
+#if ROXOR_ULTRA_LAZY_JIT
+ NODE *node = NEW_CFUNC(NULL, 0);
+ NODE *body = NEW_FBODY(NEW_METHOD(node, klass, noex), 0);
+ rb_objc_retain(body);
+
+ rb_vm_prepare_method(klass, sel, f, body);
+#else
IMP imp = GET_VM()->compile(f);
-
NODE *node = NEW_CFUNC(imp, 0);
NODE *body = NEW_FBODY(NEW_METHOD(node, klass, noex), 0);
rb_objc_retain(body);
- rb_vm_define_method(klass, sel_registerName(name), imp, body, false);
+ rb_vm_define_method(klass, sel, imp, body, false);
+#endif
}
if (write) {
Function *f = compiler->compile_write_attr(iname);
+ snprintf(buf, sizeof buf, "%s=:", name);
+ SEL sel = sel_registerName(buf);
+#if ROXOR_ULTRA_LAZY_JIT
+ NODE *node = NEW_CFUNC(NULL, 1);
+ NODE *body = NEW_FBODY(NEW_METHOD(node, klass, noex), 0);
+ rb_objc_retain(body);
+
+ rb_vm_prepare_method(klass, sel, f, body);
+#else
IMP imp = GET_VM()->compile(f);
-
NODE *node = NEW_CFUNC(imp, 1);
NODE *body = NEW_FBODY(NEW_METHOD(node, klass, noex), 0);
rb_objc_retain(body);
- snprintf(buf, sizeof buf, "%s=:", name);
- rb_vm_define_method(klass, sel_registerName(buf), imp, body, false);
+ rb_vm_define_method(klass, sel, imp, body, false);
+#endif
}
delete compiler;
@@ -5160,8 +5394,6 @@
assert(node != NULL);
const rb_vm_arity_t arity = rb_vm_node_arity(node);
- assert(arity.real < MAX_ARITY);
-
const char *sel_name = sel_getName(sel);
const bool genuine_selector = sel_name[strlen(sel_name) - 1] == ':';
@@ -5438,7 +5670,8 @@
bool on_stack = false;
for (int j = callstack_n - 1; j >= 0; j--) {
void *start = NULL;
- if (GET_VM()->symbolize_call_address(callstack[j], &start, NULL, NULL, 0)) {
+ if (GET_VM()->symbolize_call_address(callstack[j],
+ &start, NULL, NULL, 0)) {
if (start == (void *)imp) {
on_stack = true;
break;
@@ -6836,6 +7069,29 @@
return Qnil; // never reached
}
+#if ROXOR_ULTRA_LAZY_JIT
+static IMP old_resolveClassMethod_imp = NULL;
+static IMP old_resolveInstanceMethod_imp = NULL;
+
+static BOOL
+resolveClassMethod_imp(void *self, SEL sel, SEL name)
+{
+ if (rb_vm_resolve_method(*(Class *)self, name)) {
+ return YES;
+ }
+ return NO; // TODO call old IMP
+}
+
+static BOOL
+resolveInstanceMethod_imp(void *self, SEL sel, SEL name)
+{
+ if (rb_vm_resolve_method((Class)self, name)) {
+ return YES;
+ }
+ return NO; // TODO call old IMP
+}
+#endif
+
extern "C"
void
Init_PreVM(void)
@@ -6844,6 +7100,22 @@
RoxorCompiler::module = new llvm::Module("Roxor");
RoxorVM::current = new RoxorVM();
+
+#if ROXOR_ULTRA_LAZY_JIT
+ Method m;
+ Class ns_object = (Class)objc_getClass("NSObject");
+ m = class_getInstanceMethod(*(Class *)ns_object,
+ sel_registerName("resolveClassMethod:"));
+ assert(m != NULL);
+ old_resolveClassMethod_imp = method_getImplementation(m);
+ method_setImplementation(m, (IMP)resolveClassMethod_imp);
+
+ m = class_getInstanceMethod(*(Class *)ns_object,
+ sel_registerName("resolveInstanceMethod:"));
+ assert(m != NULL);
+ old_resolveInstanceMethod_imp = method_getImplementation(m);
+ method_setImplementation(m, (IMP)resolveInstanceMethod_imp);
+#endif
}
static VALUE
Modified: MacRuby/branches/experimental/roxor.h
===================================================================
--- MacRuby/branches/experimental/roxor.h 2009-04-08 05:06:27 UTC (rev 1401)
+++ MacRuby/branches/experimental/roxor.h 2009-04-09 05:07:07 UTC (rev 1402)
@@ -68,6 +68,7 @@
void rb_vm_define_method(Class klass, SEL sel, IMP imp, NODE *node, bool direct);
void rb_vm_define_attr(Class klass, const char *name, bool read, bool write, int noex);
void rb_vm_alias(VALUE klass, ID name, ID def);
+void rb_vm_copy_methods(Class from_class, Class to_class);
VALUE rb_vm_call(VALUE self, SEL sel, int argc, const VALUE *args, bool super);
VALUE rb_vm_call_with_cache(void *cache, VALUE self, SEL sel, int argc, const VALUE *argv);
VALUE rb_vm_call_with_cache2(void *cache, VALUE self, VALUE klass, SEL sel, int argc, const VALUE *argv);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090408/881621a1/attachment-0001.html>
More information about the macruby-changes
mailing list