Permalink
Browse files

Fix 'for' in 1.9 mode

This also adds the ability for a CompiledMethod to reference a constant
inside the literals tuple. These constants are resolved at
CompiledMethod load time only.
  • Loading branch information...
evanphx committed Oct 8, 2011
1 parent 9b643d3 commit 3ceb20f6a7ceb7f1d6133b821393f97ee96a2e3e
View
@@ -12,3 +12,4 @@
require path + "/compiler/compiled_file"
require path + "/compiler/evaluator"
require path + "/compiler/printers"
+require path + "/compiler/runtime"
View
@@ -734,6 +734,60 @@ def sexp_name
end
end
+ class For19Arguments < Node
+ def initialize(line, arguments)
+ @line = line
+ @arguments = arguments
+
+ if @arguments.kind_of? MultipleAssignment
+ @args = 0
+ @splat = 0
+ else
+ @args = 1
+ @splat = nil
+ end
+ end
+
+ def bytecode(g)
+ if @splat
+ g.push_literal Rubinius::Compiler::Runtime
+ g.push_local 0
+ g.send :unwrap_block_arg, 1
+ else
+ g.push_local 0
+ end
+
+ @arguments.bytecode(g)
+ g.pop
+ end
+
+ def required_args
+ @args
+ end
+
+ def total_args
+ @args
+ end
+
+ def post_args
+ 0
+ end
+
+ def splat_index
+ @splat
+ end
+ end
+
+ class For19 < For
+ def initialize(line, arguments, body)
+ @line = line
+ @arguments = For19Arguments.new line, arguments
+ @body = body || NilLiteral.new(line)
+
+ new_local :"$for_args"
+ end
+ end
+
class Negate < Node
attr_accessor :value
@@ -141,6 +141,11 @@ def unmarshal_data
str = next_bytes count
discard # remove the \n
return str.to_sym
+ when ?c
+ count = next_string.to_i
+ str = next_bytes count
+ discard
+ return str.split("::").inject(Object) { |a,n| a.const_get(n) }
when ?p
count = next_string.to_i
obj = Tuple.new(count)
@@ -305,7 +310,12 @@ def marshal(val)
str.append marshal(val.local_names)
str
else
- raise ArgumentError, "Unknown type #{val.class}: #{val.inspect}"
+ if val.respond_to? :rbx_marshal_constant
+ name = StringValue(val.rbx_marshal_constant)
+ "c\n#{name.size}\n#{name}\n"
+ else
+ raise ArgumentError, "Unknown type #{val.class}: #{val.inspect}"
+ end
end
end
end
View
@@ -0,0 +1,19 @@
+module Rubinius
+ module Compiler::Runtime
+ def unwrap_block_arg(arg)
+ if arg.size == 1
+ elem = arg.at(0)
+ return elem if elem.kind_of?(Array)
+ end
+
+ arg
+ end
+
+ module_function :unwrap_block_arg
+
+ def self.rbx_marshal_constant
+ name
+ end
+ end
+end
+
@@ -541,6 +541,12 @@ def process_iter(line, method_send, scope)
method_send
end
+ def process_for(line, iter, arguments, body)
+ send = AST::Send.new line, iter, :each
+ send.block = AST::For19.new line, arguments, body
+ send
+ end
+
def process_lambda(line, scope)
arguments = scope.array.shift
if scope.array.size == 1
View
@@ -16,6 +16,10 @@
gcc.cflags << "-O2"
end
+ if ENV['POKE']
+ gcc.mtime_only = true
+ end
+
# This is necessary for the gcc sync prims to fully work
if Rubinius::BUILD_CONFIG[:x86_32]
gcc.cflags << "-march=i686"
View
@@ -13,7 +13,14 @@
d = new_block_generator(g)
- d.cast_for_single_block_arg
+ ruby_version_is ""..."1.9" do
+ d.cast_for_single_block_arg
+ end
+
+ ruby_version_is "1.9" do
+ d.push_local 0
+ end
+
d.set_local_depth 1, 0
d.pop
@@ -49,7 +56,14 @@
d = new_block_generator(g)
- d.cast_for_single_block_arg
+ ruby_version_is ""..."1.9" do
+ d.cast_for_single_block_arg
+ end
+
+ ruby_version_is "1.9" do
+ d.push_local 0
+ end
+
d.set_local_depth 1, 0
d.pop
@@ -76,7 +90,17 @@
compile do |g|
d = new_block_generator(g)
- d.cast_for_multi_block_arg
+ ruby_version_is ""..."1.9" do
+ d.cast_for_multi_block_arg
+ end
+
+ ruby_version_is "1.9" do
+ d.push_literal Rubinius::Compiler::Runtime
+ d.push_local 0
+ d.send :unwrap_block_arg, 1
+ d.cast_array
+ end
+
d.shift_array
d.set_local_depth 1, 0
d.pop
@@ -109,7 +133,14 @@
d = new_block_generator(g)
- d.cast_for_single_block_arg
+ ruby_version_is ""..."1.9" do
+ d.cast_for_single_block_arg
+ end
+
+ ruby_version_is "1.9" do
+ d.push_local 0
+ end
+
d.set_local_depth 1, 0
d.pop
@@ -147,7 +178,14 @@
# outer for
d = new_block_generator(g)
- d.cast_for_single_block_arg
+ ruby_version_is ""..."1.9" do
+ d.cast_for_single_block_arg
+ end
+
+ ruby_version_is "1.9" do
+ d.push_local 0
+ end
+
d.set_local_depth 1, 1
d.pop
@@ -160,7 +198,14 @@
# inner for
e = new_block_generator(g)
- e.cast_for_single_block_arg
+ ruby_version_is ""..."1.9" do
+ e.cast_for_single_block_arg
+ end
+
+ ruby_version_is "1.9" do
+ e.push_local 0
+ end
+
e.set_local_depth 2, 2
e.pop
@@ -12,6 +12,8 @@
#include "object_utils.hpp"
#include "instruments/timing.hpp"
+#include "configuration.hpp"
+
namespace rubinius {
BytecodeVerification::BytecodeVerification(CompiledMethod* cm)
: method_(cm)
@@ -64,6 +66,52 @@ namespace rubinius {
return false;
}
+ // FIXME
+ //
+ // This is conditional because in 1.8 mode, CM's for blocks have arity
+ // info that isn't used, but therefore fails these checks because
+ // of the way 'for' works.
+ //
+ // FIXME
+ if(LANGUAGE_19_ENABLED(state) || LANGUAGE_20_ENABLED(state)) {
+ if(Fixnum* fix = try_as<Fixnum>(method_->splat())) {
+ if(fix->to_native() >= locals_) {
+ fail("invalid splat position", -1);
+ return false;
+ }
+ }
+
+ Fixnum* tot = try_as<Fixnum>(method_->total_args());
+ Fixnum* req = try_as<Fixnum>(method_->required_args());
+ Fixnum* post = try_as<Fixnum>(method_->post_args());
+
+ if(!tot || !req || !post) {
+ fail("method not initialized properly (missing arg counts)", -1);
+ return false;
+ }
+
+ if(tot->to_native() > locals_) {
+ fail("more arguments than local slots", -1);
+ return false;
+ }
+
+ if(req->to_native() > tot->to_native()) {
+ fail("more required arguments than total", -1);
+ return false;
+ }
+
+ if(post->to_native() > req->to_native()) {
+ fail("more post arguments than required", -1);
+ return false;
+ }
+
+ if(post->to_native() > tot->to_native()) {
+ fail("more post arguments than total", -1);
+ return false;
+ }
+
+ }
+
total_ = ops_->num_fields();
stack_ = new int32_t[total_];
View
@@ -26,6 +26,18 @@ namespace rubinius {
using std::endl;
+ Object* UnMarshaller::get_constant() {
+ char data[1024];
+ size_t count;
+
+ stream >> count;
+ stream.get();
+ stream.read(data, count + 1);
+ data[count] = 0; // clamp
+
+ return state->path2class(data);
+ }
+
Object* UnMarshaller::get_int() {
char data[1024];
@@ -192,6 +204,8 @@ namespace rubinius {
return get_iseq();
case 'M':
return get_cmethod();
+ case 'c':
+ return get_constant();
default:
std::string str = "unknown marshal code: ";
str.append( 1, code );
View
@@ -37,6 +37,7 @@ namespace rubinius {
Float* get_float();
InstructionSequence* get_iseq();
CompiledMethod* get_cmethod();
+ Object* get_constant();
public:
class Error {
View
@@ -339,6 +339,34 @@ namespace rubinius {
mod->set_const(this, (char*)name, val);
}
+ Object* VM::path2class(const char* path) {
+ Module* mod = shared.globals.object.get();
+
+ char* copy = strdup(path);
+ char* cur = copy;
+
+ for(;;) {
+ char* pos = strstr(cur, "::");
+ if(pos) *pos = 0;
+
+ Object* obj = mod->get_const(this, symbol(cur));
+
+ if(pos) {
+ if(Module* m = try_as<Module>(obj)) {
+ mod = m;
+ } else {
+ free(copy);
+ return Qnil;
+ }
+ } else {
+ free(copy);
+ return obj;
+ }
+
+ cur = pos + 2;
+ }
+ }
+
void VM::print_backtrace() {
abort();
}
View
@@ -367,6 +367,8 @@ namespace rubinius {
void set_const(const char* name, Object* val);
void set_const(Module* mod, const char* name, Object* val);
+ Object* path2class(const char* name);
+
#ifdef ENABLE_LLVM
llvm::Module* llvm_module();
void llvm_cleanup();

0 comments on commit 3ceb20f

Please sign in to comment.