Permalink
Browse files

Setup top level visibility and script attributes

This creates a tag for a call frame indicating it's a top level script
or the top level for visibility checks. For this we also support a
boolean value on call_under definining whether to open a new visibility
top level or not.

This can be used to fix visibility checks and have methods defined
inside blocks have the proper visibility in Rubinius.

Fixes #2316 and #2089
  • Loading branch information...
1 parent dc6497b commit add25be721988dc53142cfe3c76bd87ee324f432 @dbussink dbussink committed May 3, 2013
@@ -12,7 +12,7 @@ def call(*args)
raise PrimitiveFailure, "BlockEnvironment#call primitive failed"
end
- def call_under(recv, constant_scope, *args)
+ def call_under(recv, constant_scope, visibility_scope, *args)
Rubinius.primitive :block_call_under
raise PrimitiveFailure, "BlockEnvironment#call_under primitive failed"
end
@@ -27,6 +27,16 @@ def locals
raise PrimitiveFailure, "Rubinius::VariableScope#locals primitive failed"
end
+ def top_level_visibility?
+ Rubinius.primitive :variable_scope_top_level_visibility
+ raise PrimitiveFailure, "Rubinius::VariableScope#top_level_visibility primitive failed"
+ end
+
+ def script?
+ Rubinius.primitive :variable_scope_script
+ raise PrimitiveFailure, "Rubinius::VariableScope#script primitive failed"
+ end
+
# To handle Module#private, protected
attr_accessor :method_visibility
end
@@ -72,7 +72,7 @@ def make_independent
end
def call_on_instance(obj, *args)
- call_under obj, @compiled_code.scope, *args
+ call_under obj, @compiled_code.scope, false, *args
end
def arity
View
@@ -99,7 +99,7 @@ def module_eval(string=undefined, filename="(eval)", line=1, &prc)
# Return a copy of the BlockEnvironment with the receiver set to self
env = prc.block
constant_scope = env.repoint_scope self
- return env.call_under(self, constant_scope, self)
+ return env.call_under(self, constant_scope, true, self)
elsif string.equal?(undefined)
raise ArgumentError, 'block not supplied'
end
@@ -117,7 +117,7 @@ def module_eval(string=undefined, filename="(eval)", line=1, &prc)
be = Rubinius::Compiler.construct_block string, binding,
filename, line
- be.call_under self, cs, self
+ be.call_under self, cs, true, self
end
alias_method :class_eval, :module_eval
View
@@ -42,7 +42,7 @@ def instance_eval(string=nil, filename="(eval)", line=1, &prc)
constant_scope = env.disable_scope!
end
- return env.call_under(self, constant_scope, self)
+ return env.call_under(self, constant_scope, true, self)
elsif string
string = StringValue(string)
@@ -101,6 +101,6 @@ def instance_exec(*args, &prc)
constant_scope = constant_scope.using_current_as(sc)
end
- return env.call_under(self, constant_scope, *args)
+ return env.call_under(self, constant_scope, true, *args)
end
end
View
@@ -42,7 +42,7 @@ def instance_eval(string=nil, filename="(eval)", line=1, &prc)
constant_scope = env.disable_scope!
end
- return env.call_under(self, constant_scope, self)
+ return env.call_under(self, constant_scope, true, self)
elsif string
string = ::Kernel.StringValue(string)
@@ -100,6 +100,6 @@ def instance_exec(*args, &prc)
constant_scope = constant_scope.using_current_as(sc)
end
- return env.call_under(self, constant_scope, *args)
+ return env.call_under(self, constant_scope, true, *args)
end
end
View
@@ -406,7 +406,7 @@ def module_exec(*args, &prc)
env = prc.block
constant_scope = env.repoint_scope self
- return env.call_under(self, constant_scope, *args)
+ return env.call_under(self, constant_scope, true, *args)
end
alias_method :class_exec, :module_exec
@@ -133,32 +133,17 @@ def super_method_defined?
return false
end
- # Indicates if this scope is for the running of a script body
- def for_script?
- if script = @method.scope.script
- return script.compiled_code == @method
- end
-
- return false
- end
-
def method_visibility
- if scr = method.scope.script and scr.eval?
- if scr.eval_binding
- return scr.eval_binding.variables.method_visibility
- else
- return @method_visibility
- end
- end
-
return @method_visibility if @method_visibility
# if this scope is for a script, and there is no method_visibility
# already set, then we default to private.
#
# This is so that a script body has it's visibility default to private.
- return :private if for_script?
+ return :private if script?
+ return nil if top_level_visibility?
+ return @parent.method_visibility if @parent
# The default, let the caller sort it out.
return nil
@@ -172,7 +172,8 @@ def attach_and_call(g, arg_name, scoped=false, pass_block=false)
g.create_block meth
g.swap
g.push_scope
- g.send :call_under, 2
+ g.push_true
+ g.send :call_under, 3
return meth
end
@@ -51,7 +51,8 @@ class ::Y
g.swap
g.push_scope
- g.send :call_under, 2
+ g.push_true
+ g.send :call_under, 3
end
end
@@ -424,7 +424,8 @@ class a::F
g.swap
g.push_scope
- g.send :call_under, 2
+ g.push_true
+ g.send :call_under, 3
end
end
@@ -459,7 +460,8 @@ class F < a
g.swap
g.push_scope
- g.send :call_under, 2
+ g.push_true
+ g.send :call_under, 3
end
end
@@ -554,7 +556,8 @@ module a::M
g.swap
g.push_scope
- g.send :call_under, 2
+ g.push_true
+ g.send :call_under, 3
end
end
end
@@ -40,7 +40,8 @@ module ::Y
g.swap
g.push_scope
- g.send :call_under, 2
+ g.push_true
+ g.send :call_under, 3
end
end
@@ -24,7 +24,8 @@ class << self
g.swap
g.push_scope
- g.send :call_under, 2
+ g.push_true
+ g.send :call_under, 3
end
end
@@ -59,7 +60,8 @@ class B
d.swap
d.push_scope
- d.send :call_under, 2
+ d.push_true
+ d.send :call_under, 3
d.pop
d.in_class :B
@@ -361,7 +361,8 @@ def in_class(name)
g.swap
g.push_scope
- g.send :call_under, 2
+ g.push_true
+ g.send :call_under, 3
end
def in_singleton_method(name, sing)
@@ -446,7 +447,8 @@ def in_module(name)
g.swap
g.push_scope
- g.send :call_under, 2
+ g.push_true
+ g.send :call_under, 3
end
def save_exception
@@ -7,6 +7,7 @@
#include "builtin/symbol.hpp"
#include "builtin/block_environment.hpp"
+#include "builtin/variable_scope.hpp"
#include "objectmemory.hpp"
#include "vm/object_utils.hpp"
@@ -409,9 +410,9 @@ namespace rubinius {
Executable* exec, Module* mod,
Arguments& args)
{
- if(args.total() < 2) {
+ if(args.total() < 3) {
Exception* exc =
- Exception::make_argument_error(state, 2, args.total(),
+ Exception::make_argument_error(state, 3, args.total(),
compiled_code_->name());
exc->locations(state, Location::from_call_stack(state, call_frame));
state->raise_exception(exc);
@@ -420,8 +421,10 @@ namespace rubinius {
Object* recv = args.shift(state);
ConstantScope* constant_scope = as<ConstantScope>(args.shift(state));
+ Object* visibility_scope = args.shift(state);
- BlockInvocation invocation(recv, constant_scope, 0);
+ int flags = CBOOL(visibility_scope) ? CallFrame::cTopLevelVisibility : 0;
+ BlockInvocation invocation(recv, constant_scope, flags);
return invoke(state, call_frame, this, args, invocation);
}
View
@@ -5,6 +5,7 @@
#include "builtin/symbol.hpp"
#include "builtin/string.hpp"
#include "builtin/nativemethod.hpp"
+#include "builtin/variable_scope.hpp"
#include "vm.hpp"
View
@@ -12,6 +12,7 @@
#include "builtin/string.hpp"
#include "builtin/symbol.hpp"
#include "builtin/tuple.hpp"
+#include "builtin/variable_scope.hpp"
#include "vm.hpp"
#include "vm/object_utils.hpp"
View
@@ -54,6 +54,7 @@
#include "builtin/constantscope.hpp"
#include "builtin/block_environment.hpp"
+#include "builtin/variable_scope.hpp"
#include "builtin/system.hpp"
#include "signal.hpp"
@@ -65,7 +65,7 @@ namespace rubinius {
scope->number_of_locals_ = locals->num_fields();
scope->isolated_ = true;
scope->locals_ = 0;
- scope->block_as_method_ = 0;
+ scope->flags_ = 0;
return scope;
}
@@ -150,6 +150,14 @@ namespace rubinius {
return ary[pos];
}
+ Object* VariableScope::top_level_visibility(STATE) {
+ return RBOOL(top_level_visibility_p());
+ }
+
+ Object* VariableScope::script(STATE) {
+ return RBOOL(script_p());
+ }
+
void VariableScope::flush_to_heap(STATE) {
if(isolated_) return;
if(!atomic::compare_and_swap(&isolated_, 0, 1)) return;
@@ -1,6 +1,7 @@
#ifndef RBX_VARIABLE_SCOPE_HPP
#define RBX_VARIABLE_SCOPE_HPP
+#include "call_frame.hpp"
#include "vm/object_utils.hpp"
#include "builtin/object.hpp"
@@ -10,7 +11,6 @@ namespace rubinius {
class CompiledCode;
class Module;
- struct CallFrame;
class Fiber;
/**
@@ -40,7 +40,7 @@ namespace rubinius {
Object** locals_;
int number_of_locals_;
int isolated_;
- int block_as_method_;
+ int flags_;
public: /* Accessors */
attr_accessor(block, Object);
@@ -63,11 +63,15 @@ namespace rubinius {
}
bool block_as_method_p() {
- return block_as_method_ == 1;
+ return flags_ & CallFrame::cBlockAsMethod;
}
- void set_block_as_method(bool val) {
- block_as_method_ = (val ? 1 : 0);
+ bool top_level_visibility_p() {
+ return flags_ & CallFrame::cTopLevelVisibility;
+ }
+
+ bool script_p() {
+ return flags_ & CallFrame::cScript;
}
void set_local(int pos, Object* val);
@@ -102,6 +106,12 @@ namespace rubinius {
// Rubinius.primitive :variable_scope_method_visibility
Object* method_visibility(STATE);
+ // Rubinius.primitive :variable_scope_top_level_visibility
+ Object* top_level_visibility(STATE);
+
+ // Rubinius.primitive :variable_scope_script
+ Object* script(STATE);
+
public: // Rubinius Type stuff
class Info : public TypeInfo {
public:
View
@@ -4,9 +4,9 @@
#include "machine_code.hpp"
#include "unwind_info.hpp"
#include "stack_variables.hpp"
-#include "builtin/variable_scope.hpp"
#include "dispatch.hpp"
#include "arguments.hpp"
+#include "object_utils.hpp"
#include "builtin/symbol.hpp"
#include <ostream>
@@ -19,6 +19,7 @@ namespace rubinius {
class Module;
class VariableScope;
class NativeMethodFrame;
+ class BlockEnvironment;
namespace jit {
class RuntimeData;
@@ -36,7 +37,9 @@ namespace rubinius {
cJITed = 1 << 6,
cBlock = 1 << 7,
cInlineBlock = 1 << 8,
- cNativeMethod = 1 << 9
+ cNativeMethod = 1 << 9,
+ cTopLevelVisibility = 1 << 10,
+ cScript = 1 << 11
};
CallFrame* previous;
Oops, something went wrong.

1 comment on commit add25be

@kachick
Member
kachick commented on add25be May 3, 2013

🍣

Thank you. #2089 run on HEAD.

Please sign in to comment.