Skip to content

Commit

Permalink
fix lexical const lookup bugs inside modules defined using the :: not…
Browse files Browse the repository at this point in the history
…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
lrz committed Feb 22, 2011
1 parent 8103151 commit 8e0123e
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 45 deletions.
55 changes: 45 additions & 10 deletions compiler.cpp
Expand Up @@ -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);\
Expand Down Expand Up @@ -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;\
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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 *
Expand Down Expand Up @@ -2067,26 +2073,40 @@ 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) {
// Bar::Foo
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();
}
}
Expand Down Expand Up @@ -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));
Expand All @@ -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;
}
Expand Down Expand Up @@ -3914,13 +3936,26 @@ 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));
Function *f = cast<Function>(val);
GET_CORE()->optimize(f);
DEBUG_LEVEL_DEC();

outer_mask = old_outer_mask;

ivars_slots_cache = old_ivars_slots_cache;

block_declaration = old_block_declaration;
Expand Down Expand Up @@ -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
}
}
Expand Down
3 changes: 2 additions & 1 deletion compiler.h
Expand Up @@ -143,6 +143,7 @@ class RoxorCompiler {
int return_from_block_ids;
bool block_declaration;
AllocaInst *dispatch_argv;
long outer_mask;

Function *writeBarrierFunc;
Function *dispatchFunc;
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 8 additions & 5 deletions kernel.c
Expand Up @@ -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);

Expand All @@ -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;
}

Expand Down
3 changes: 0 additions & 3 deletions 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
50 changes: 25 additions & 25 deletions vm.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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.
Expand All @@ -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);
Expand Down
11 changes: 10 additions & 1 deletion vm.h
Expand Up @@ -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,
Expand Down Expand Up @@ -564,6 +572,7 @@ struct icache *rb_vm_ivar_slot_allocate(void);

struct ccache {
VALUE outer;
uint64_t outer_mask;
VALUE val;
};

Expand Down

0 comments on commit 8e0123e

Please sign in to comment.