Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

fix lexical const lookup bugs inside modules defined using the :: not…

…ation + attach necessary dwarf metadata to const lookup primitive calls in order for const_missing to properly appear in backtraces

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@5236 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
commit 8e0123ecc5bd289c4f4c16fa5275e913c93dd1b1 1 parent 8103151
Laurent Sansonetti authored
View
55 compiler.cpp
@@ -75,7 +75,8 @@ RoxorCompiler *RoxorCompiler::shared = NULL;
__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 @@ RoxorCompiler *RoxorCompiler::shared = NULL;
__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 @@ RoxorCompiler *RoxorCompiler::shared = NULL;
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 @@ RoxorCompiler::compile_constant_declaration(NODE *node, Value *val)
}
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 @@ RoxorCompiler::compile_const(ID id, Value *outer)
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 @@ RoxorCompiler::compile_set_has_ensure(Value *val)
}
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 @@ RoxorCompiler::compile_class_path(NODE *node, int *flags)
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 @@ RoxorCompiler::compile_node0(NODE *node)
{
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 @@ RoxorCompiler::compile_node0(NODE *node)
}
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 @@ RoxorCompiler::compile_node0(NODE *node)
= 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 @@ RoxorCompiler::compile_node0(NODE *node)
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 @@ RoxorCompiler::compile_node0(NODE *node)
{
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
}
}
View
3  compiler.h
@@ -143,6 +143,7 @@ class RoxorCompiler {
int return_from_block_ids;
bool block_declaration;
AllocaInst *dispatch_argv;
+ long outer_mask;
Function *writeBarrierFunc;
Function *dispatchFunc;
@@ -381,7 +382,7 @@ class RoxorCompiler {
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);
View
13 kernel.c
@@ -139,9 +139,10 @@ vm_cvar_set(VALUE klass, ID id, VALUE val, unsigned char dynamic_class)
}
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 @@ vm_get_const(VALUE outer, void *cache_p, ID path, int flags)
}
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;
}
View
3  spec/frozen/tags/macruby/language/constants_tags.txt
@@ -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
View
50 vm.cpp
@@ -762,6 +762,7 @@ RoxorCore::constant_cache_get(ID path)
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 @@ rb_const_get_direct(VALUE klass, ID id)
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 @@ rb_vm_define_class(ID path, VALUE outer, VALUE super, int flags,
}
}
- // 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_vm_define_class(ID path, VALUE outer, VALUE super, int flags,
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);
View
11 vm.h
@@ -319,7 +319,15 @@ int rb_vm_thread_safe_level(rb_vm_thread_t *thread);
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 icache *rb_vm_ivar_slot_allocate(void);
struct ccache {
VALUE outer;
+ uint64_t outer_mask;
VALUE val;
};
Please sign in to comment.
Something went wrong with that request. Please try again.