[macruby-changes] [5236] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Feb 21 19:14:56 PST 2011


Revision: 5236
          http://trac.macosforge.org/projects/ruby/changeset/5236
Author:   lsansonetti at apple.com
Date:     2011-02-21 19:14:53 -0800 (Mon, 21 Feb 2011)
Log Message:
-----------
fix lexical const lookup bugs inside modules defined using the :: notation + attach necessary dwarf metadata to const lookup primitive calls in order for const_missing to properly appear in backtraces

Modified Paths:
--------------
    MacRuby/trunk/compiler.cpp
    MacRuby/trunk/compiler.h
    MacRuby/trunk/kernel.c
    MacRuby/trunk/spec/frozen/tags/macruby/language/constants_tags.txt
    MacRuby/trunk/vm.cpp
    MacRuby/trunk/vm.h

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2011-02-19 11:27:24 UTC (rev 5235)
+++ MacRuby/trunk/compiler.cpp	2011-02-22 03:14:53 UTC (rev 5236)
@@ -75,7 +75,8 @@
     __save_state(PHINode *, ensure_pn);\
     __save_state(NODE *, ensure_node);\
     __save_state(bool, block_declaration);\
-    __save_state(AllocaInst *, dispatch_argv);
+    __save_state(AllocaInst *, dispatch_argv);\
+    __save_state(uint64_t, outer_mask);
 
 #define restore_compiler_state() \
     __restore_state(current_line);\
@@ -109,7 +110,8 @@
     __restore_state(ensure_pn);\
     __restore_state(ensure_node);\
     __restore_state(block_declaration);\
-    __restore_state(dispatch_argv);
+    __restore_state(dispatch_argv);\
+    __restore_state(outer_mask);
 
 #define reset_compiler_state() \
     bb = NULL;\
@@ -142,7 +144,8 @@
     ensure_pn = NULL;\
     ensure_node = NULL;\
     block_declaration = false;\
-    dispatch_argv = NULL;
+    dispatch_argv = NULL;\
+    outer_mask = 0;
 
 RoxorCompiler::RoxorCompiler(bool _debug_mode)
 {
@@ -1510,7 +1513,7 @@
     }
     else {
 	assert(node->nd_else != NULL);
-	args[0] = compile_class_path(node->nd_else, &flags);
+	args[0] = compile_class_path(node->nd_else, &flags, NULL);
 	assert(node->nd_else->nd_mid > 0);
 	args[1] = compile_id(node->nd_else->nd_mid);
     }
@@ -1612,11 +1615,14 @@
 
     Value *args[] = {
 	outer,
+	ConstantInt::get(Int64Ty, outer_mask),
 	compile_ccache(id),
 	compile_id(id),
 	ConstantInt::get(Int32Ty, flags)
     };
-    return compile_protected_call(getConstFunc, args, args + 4);
+    Instruction *insn = compile_protected_call(getConstFunc, args, args + 5);
+    attach_current_line_metadata(insn);
+    return insn;
 }
 
 Value *
@@ -2067,13 +2073,16 @@
 }
 
 Value *
-RoxorCompiler::compile_class_path(NODE *node, int *flags)
+RoxorCompiler::compile_class_path(NODE *node, int *flags, int *outer_level)
 {
     if (nd_type(node) == NODE_COLON3) {
 	// ::Foo
 	if (flags != NULL) {
 	    *flags = 0;
 	}
+	if (outer_level != NULL) {
+	    *outer_level = 0;
+	}
 	return compile_nsobject();
     }
     else if (node->nd_head != NULL) {
@@ -2081,12 +2090,23 @@
 	if (flags != NULL) {
 	    *flags = DEFINE_SUB_OUTER;
 	}
+	if (outer_level != NULL) {
+	    // Count the number of outers minus the current one.
+	    int level = 0;
+	    for (NODE *n = node; n != NULL; n = n->nd_next) {
+		level++;
+	    }
+	    *outer_level = level + 1;
+	}
 	return compile_node(node->nd_head);
     }
     else {
 	if (flags != NULL) {
 	    *flags = DEFINE_OUTER;
 	}
+	if (outer_level != NULL) {
+	    *outer_level = 0;
+	}
 	return compile_current_class();
     }
 }
@@ -3842,7 +3862,8 @@
 	    {
 		assert(node->nd_cpath != NULL);
 
-		Value *classVal;
+		Value *classVal = NULL;
+		int current_outer_level = 0;
 		if (nd_type(node) == NODE_SCLASS) {
 		    classVal =
 			compile_singleton_class(compile_node(node->nd_recv));
@@ -3865,7 +3886,8 @@
 		    }
 
 		    int flags = 0;
-		    Value *cpath = compile_class_path(node->nd_cpath, &flags);
+		    Value *cpath = compile_class_path(node->nd_cpath, &flags,
+			&current_outer_level);
 		    if (nd_type(node) == NODE_MODULE) {
 			flags |= DEFINE_MODULE;
 		    }
@@ -3914,6 +3936,17 @@
 			    = ivars_slots_cache;
 			old_ivars_slots_cache.clear();
 
+			uint64_t old_outer_mask = outer_mask;
+			if (current_outer_level > 0) {
+			    outer_mask <<= current_outer_level;
+			    for (int i = 0; i < current_outer_level; i++) {
+				outer_mask |= (1 << i + 1);
+			    } 
+			}
+			else {
+			    outer_mask <<= 1;
+			}
+
 			DEBUG_LEVEL_INC();
 			Value *val = compile_node(body);
 			assert(Function::classof(val));
@@ -3921,6 +3954,8 @@
 			GET_CORE()->optimize(f);
 			DEBUG_LEVEL_DEC();
 
+			outer_mask = old_outer_mask;
+
 			ivars_slots_cache = old_ivars_slots_cache;
 
 			block_declaration = old_block_declaration;
@@ -4635,13 +4670,13 @@
 	    {
 		assert(node->nd_mid > 0);
 		if (rb_is_const_id(node->nd_mid)) {
-		    // Constant
+		    // Constant.
 		    assert(node->nd_head != NULL);
 		    return compile_const(node->nd_mid,
 			    compile_node(node->nd_head));
 		}
 		else {
-		    // Method call
+		    // Method call.
 		    abort(); // TODO
 		}
 	    }

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2011-02-19 11:27:24 UTC (rev 5235)
+++ MacRuby/trunk/compiler.h	2011-02-22 03:14:53 UTC (rev 5236)
@@ -143,6 +143,7 @@
 	int return_from_block_ids;
 	bool block_declaration;
 	AllocaInst *dispatch_argv;
+	long outer_mask;
 
 	Function *writeBarrierFunc;
 	Function *dispatchFunc;
@@ -381,7 +382,7 @@
 	Value *compile_current_class(void);
 	virtual Value *compile_nsobject(void);
 	virtual Value *compile_standarderror(void);
-	Value *compile_class_path(NODE *node, int *flags);
+	Value *compile_class_path(NODE *node, int *flags, int *outer_level);
 	Value *compile_const(ID id, Value *outer);
 	Value *compile_singleton_class(Value *obj);
 	Value *compile_defined_expression(NODE *node);

Modified: MacRuby/trunk/kernel.c
===================================================================
--- MacRuby/trunk/kernel.c	2011-02-19 11:27:24 UTC (rev 5235)
+++ MacRuby/trunk/kernel.c	2011-02-22 03:14:53 UTC (rev 5236)
@@ -139,9 +139,10 @@
 }
 
 PRIMITIVE VALUE
-vm_get_const(VALUE outer, void *cache_p, ID path, int flags)
+vm_get_const(VALUE outer, uint64_t outer_mask, void *cache_p, ID path,
+	int flags)
 {
-    struct ccache *cache = (struct ccache *) cache_p;
+    struct ccache *cache = (struct ccache *)cache_p;
     const bool lexical_lookup = (flags & CONST_LOOKUP_LEXICAL);
     const bool dynamic_class = (flags & CONST_LOOKUP_DYNAMIC_CLASS);
 
@@ -153,15 +154,17 @@
     }
 
     VALUE val;
-    if (cache->outer == outer && cache->val != Qundef) {
+    if (cache->outer == outer && cache->outer_mask == outer_mask
+	    && cache->val != Qundef) {
 	val = cache->val;
     }
     else {
-	val = rb_vm_const_lookup(outer, path, lexical_lookup, false);
+	val = rb_vm_const_lookup_level(outer, outer_mask, path,
+		lexical_lookup, false);
 	cache->outer = outer;
+	cache->outer_mask = outer_mask;
 	cache->val = val;
     }
-
     return val;
 }
 

Modified: MacRuby/trunk/spec/frozen/tags/macruby/language/constants_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/language/constants_tags.txt	2011-02-19 11:27:24 UTC (rev 5235)
+++ MacRuby/trunk/spec/frozen/tags/macruby/language/constants_tags.txt	2011-02-22 03:14:53 UTC (rev 5236)
@@ -1,5 +1,2 @@
 fails:Constant resolution within methods with statically assigned constants searches Object as a lexical scope only if Object is explicitly opened
-fails:Constant resolution within methods with statically assigned constants does not search the lexical scope of qualifying modules
 fails:Constant resolution within methods with dynamically assigned constants searches Object as a lexical scope only if Object is explicitly opened
-fails:Constant resolution within methods with dynamically assigned constants does not search the lexical scope of qualifying modules
-fails:Constant resolution within methods with dynamically assigned constants searches the lexical scope of a block

Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp	2011-02-19 11:27:24 UTC (rev 5235)
+++ MacRuby/trunk/vm.cpp	2011-02-22 03:14:53 UTC (rev 5236)
@@ -762,6 +762,7 @@
     if (iter == ccache.end()) {
 	struct ccache *cache = (struct ccache *)malloc(sizeof(struct ccache));
 	cache->outer = 0;
+	cache->outer_mask = 0;
 	cache->val = Qundef;
 	ccache[path] = cache;
 	return cache;
@@ -1233,21 +1234,31 @@
 
 extern "C"
 VALUE
-rb_vm_const_lookup(VALUE outer, ID path, bool lexical, bool defined)
+rb_vm_const_lookup_level(VALUE outer, uint64_t outer_mask, ID path,
+	bool lexical, bool defined)
 {
     rb_vm_check_if_module(outer);
+
     if (lexical) {
 	// Let's do a lexical lookup before a hierarchical one, by looking for
 	// the given constant in all modules under the given outer.
 	GET_CORE()->lock();
 	struct rb_vm_outer *o = GET_CORE()->get_outer((Class)outer);
+	uint64_t n = 0;
 	while (o != NULL && o->klass != (Class)rb_cNSObject) {
-	    VALUE val = rb_const_get_direct((VALUE)o->klass, path);
-	    if (val != Qundef) {
-		GET_CORE()->unlock();
-		return defined ? Qtrue : val;
+	    // If the current outer isn't in the mask, it means we can use it
+	    // for const lookup. The outer mask is used when performing const
+	    // lookups inside modules defined using the :: notation
+	    // (ex: class A::B; class C; class D::E; ...)
+	    if (!(outer_mask & (1 << n))) {
+		VALUE val = rb_const_get_direct((VALUE)o->klass, path);
+		if (val != Qundef) {
+		    GET_CORE()->unlock();
+		    return defined ? Qtrue : val;
+		}
 	    }
 	    o = o->outer;
+	    n++;
 	}
 	GET_CORE()->unlock();
     }
@@ -1360,25 +1371,6 @@
 	}
     }
 
-    // Prepare the constant outer.
-    VALUE const_outer;
-    if (flags & DEFINE_OUTER) {
-	const_outer = outer;
-    }
-    else if (flags & DEFINE_SUB_OUTER) {
-	// The Foo::Bar case, the outer here is the outer of the outer.
-	rb_vm_outer_t *o = GET_CORE()->get_outer((Class)outer);
-	if (o != NULL && o->outer != NULL) {
-	    const_outer = (VALUE)o->outer->klass;
-	}
-	else {
-	    const_outer = rb_cObject;
-	}
-    }
-    else {
-	const_outer = rb_cObject;
-    }
-
     VALUE klass = get_klass_const(outer, path, dynamic_class);
     if (klass != Qundef) {
 	// Constant is already defined.
@@ -1388,9 +1380,17 @@
 			rb_class2name(klass));
 	    }
 	}
-	rb_vm_set_outer(klass, const_outer);
     }
     else {
+	// Prepare the constant outer.
+	VALUE const_outer;
+	if ((flags & DEFINE_OUTER) || (flags & DEFINE_SUB_OUTER)) {
+	    const_outer = outer;
+	}
+	else {
+	    const_outer = rb_cObject;
+	}
+
 	// Define the constant.
 	if (flags & DEFINE_MODULE) {
 	    assert(super == 0);

Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h	2011-02-19 11:27:24 UTC (rev 5235)
+++ MacRuby/trunk/vm.h	2011-02-22 03:14:53 UTC (rev 5236)
@@ -319,7 +319,15 @@
 VALUE rb_vm_top_self(void);
 void rb_vm_const_is_defined(ID path);
 VALUE rb_vm_resolve_const_value(VALUE val, VALUE klass, ID name);
-VALUE rb_vm_const_lookup(VALUE outer, ID path, bool lexical, bool defined);
+
+VALUE rb_vm_const_lookup_level(VALUE outer, uint64_t outer_mask, ID path,
+	bool lexical, bool defined);
+static inline VALUE
+rb_vm_const_lookup(VALUE outer, ID path, bool lexical, bool defined)
+{
+    return rb_vm_const_lookup_level(outer, 0, path, lexical, defined);
+}
+
 bool rb_vm_lookup_method(Class klass, SEL sel, IMP *pimp,
 	rb_vm_method_node_t **pnode);
 bool rb_vm_lookup_method2(Class klass, ID mid, SEL *psel, IMP *pimp,
@@ -564,6 +572,7 @@
 
 struct ccache {
     VALUE outer;
+    uint64_t outer_mask;
     VALUE val;
 };
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20110221/c9cb6769/attachment-0001.html>


More information about the macruby-changes mailing list