Revision: 5236 http://trac.macosforge.org/projects/ruby/changeset/5236 Author: lsansonetti@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, + ¤t_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; };
participants (1)
-
source_changes@macosforge.org