Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fix Autoload in VM

The VM, after looking up a constant, will see if the result is an
instance of Autoload. If so, it sends call to the object.
  • Loading branch information...
commit 1a2ea43f813b545acd66069ff668e7d37d54a27c 1 parent cc3a728
Evan Phoenix authored
View
8 kernel/common/autoload.rb
@@ -2,6 +2,10 @@
# Used to implement Module#autoload.
class Autoload
+ def self.allocate
+ Ruby.primitive :autoload_allocate
+ end
+
attr_reader :name
attr_reader :scope
attr_reader :path
@@ -11,7 +15,7 @@ def initialize(name, scope, path)
@name = name
@scope = scope
@original_path = path
- @path, = __split_path__(path)
+ @path, = Compile.split_path(path)
Autoload.add(self)
end
@@ -49,7 +53,7 @@ def add(al)
def remove(path)
al = autoloads.delete(path)
return unless al
- al.each {|a| a.discard }
+ al.each { |a| a.discard }
end
end
end
View
5 kernel/common/compile.rb
@@ -443,13 +443,13 @@ def load(path, opts = {:wrap => false, :recompile => false})
#
def require(path)
path = StringValue(path)
- rb, rbc, ext = __split_path__ path
+ rb, rbc, ext = Compile.split_path path
Autoload.remove(rb)
Compile.unified_load path, rb, rbc, ext, true
end
module_function :require
- def __split_path__(path)
+ def Compile.split_path(path)
# Remap all library extensions behind the scenes, just like MRI
path.gsub!(/\.(so|bundle|dll|dylib)$/, "#{Rubinius::LIBSUFFIX}")
@@ -464,6 +464,5 @@ def __split_path__(path)
end
return rb,rbc,ext
end
- private :__split_path__
end
View
16 kernel/common/module.rb
@@ -679,7 +679,11 @@ def autoload?(name)
def remove_const(name)
sym = name.to_sym
const_missing(name) unless constants_table.has_key?(sym)
- constants_table.delete(sym)
+ val = constants_table.delete(sym)
+
+ # Silly API compac. Shield Autoload instances
+ return nil if val.kind_of? Autoload
+ val
end
private :remove_const
@@ -754,5 +758,15 @@ def valid_const_name?(name)
private :valid_const_name?
+ def initialize_copy(other)
+ @constants = @constants.dup
+ @method_table = @method_table.dup
+
+ @constants.each do |name, val|
+ if val.kind_of? Autoload
+ @constants[name] = Autoload.new(val.name, self, val.original_path)
+ end
+ end
+ end
end
View
6 spec/tags/frozen/1.8/core/module/autoload_tags.txt
@@ -1,7 +1,3 @@
-fails:Module#autoload loads constants that are registered at toplevel
-fails:Module#autoload triggers an autoload before using a toplevel constant
-fails:Module#autoload should not fail when the load path is manually required
-fails:Module#autoload should allow multiple autoload requests to reference one file
@@ -15,5 +11,3 @@ fails:Module#autoload should allow multiple autoload requests to reference one f
fails:Module#autoload doesn't call 'require' nor 'load' dynamically
-fails:Module#autoload with constant enumeration or removal doesn't trigger file load
-fails:Module#autoload uses dup copies for autoloaded constants
View
14 vm/builtin/autoload.cpp
@@ -0,0 +1,14 @@
+#include "prelude.hpp"
+#include "builtin/class.hpp"
+#include "builtin/autoload.hpp"
+
+namespace rubinius {
+ Autoload* Autoload::create(STATE) {
+ return (Autoload*)state->new_object(G(autoload));
+ }
+
+ void Autoload::init(STATE) {
+ GO(autoload).set(state->new_class("Autoload"));
+ G(autoload)->set_object_type(state, AutoloadType);
+ }
+}
View
30 vm/builtin/autoload.hpp
@@ -0,0 +1,30 @@
+#ifndef RBX_BUILTIN_AUTOLOAD_HPP
+#define RBX_BUILTIN_AUTOLOAD_HPP
+
+#include "builtin/object.hpp"
+#include "type_info.hpp"
+
+namespace rubinius {
+
+ class Autoload : public Object {
+ public:
+ const static size_t fields = 0;
+ const static object_type type = AutoloadType;
+
+ /** Register class with the VM. */
+ static void init(STATE);
+
+ // Ruby.primitive :autoload_allocate
+ static Autoload* create(STATE);
+
+ public: /* TypeInfo */
+
+ class Info : public TypeInfo {
+ public:
+ Info(object_type type) : TypeInfo(type) { }
+ };
+ };
+
+}
+
+#endif
View
6 vm/globals.hpp
@@ -102,6 +102,8 @@ namespace rubinius {
TypedRoot<Class*> data;
+ TypedRoot<Class*> autoload; /**< Autoload class */
+
/* Add new globals above this line. */
/* Leave this as the last data member always */
@@ -203,8 +205,8 @@ namespace rubinius {
nmethod(&roots),
nativectx(&roots), /**< NativeMethodContext */
-
- data(&roots)
+ data(&roots),
+ autoload(&roots)
/* Add initialize of globals above this line. */
{ }
View
20 vm/instructions.rb
@@ -682,6 +682,16 @@ def find_const(index)
bool res = task->send_message_slowly(msg);
RETURN(res);
+ } else if(kind_of<Autoload>(res)) {
+ Message& msg = *task->msg;
+ msg.recv = res;
+ msg.name = G(sym_call);
+ msg.stack = 0;
+ msg.lookup_from = res->lookup_begin(state);
+ msg.set_args(0);
+
+ bool res = task->send_message_slowly(msg);
+ RETURN(res);
}
stack_push(res);
@@ -2247,6 +2257,16 @@ def push_const(index)
bool res = task->send_message_slowly(msg);
RETURN(res);
+ } else if(kind_of<Autoload>(res)) {
+ Message& msg = *task->msg;
+ msg.recv = res;
+ msg.name = G(sym_call);
+ msg.stack = 0;
+ msg.lookup_from = res->lookup_begin(state);
+ msg.set_args(0);
+
+ bool res = task->send_message_slowly(msg);
+ RETURN(res);
}
stack_push(res);
View
2  vm/ontology.cpp
@@ -36,6 +36,7 @@
#include "builtin/time.hpp"
#include "builtin/tuple.hpp"
#include "builtin/taskprobe.hpp"
+#include "builtin/autoload.hpp"
#define SPECIAL_CLASS_MASK 0x1f
#define SPECIAL_CLASS_SIZE 32
@@ -203,6 +204,7 @@ namespace rubinius {
TaskProbe::init(this);
Exception::init(this);
Data::init(this);
+ Autoload::init(this);
NativeMethod::register_class_with(this);
NativeMethodContext::register_class_with(this);
View
2  vm/test/test_vm.hpp
@@ -62,7 +62,7 @@ class TestVM : public CxxTest::TestSuite {
}
void test_globals() {
- TS_ASSERT_EQUALS(state->globals.roots.size(), 121U);
+ TS_ASSERT_EQUALS(state->globals.roots.size(), 122U);
}
void test_collection() {
Please sign in to comment.
Something went wrong with that request. Please try again.