Skip to content

Commit

Permalink
Fixed Rubinius loading stale runtime.
Browse files Browse the repository at this point in the history
  • Loading branch information
brixen committed Jul 26, 2012
1 parent c23def8 commit 3ce0d8a
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 37 deletions.
50 changes: 35 additions & 15 deletions rakelib/kernel.rake
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ end
# Compile all compiler files during build stage
opcodes = "lib/compiler/opcodes.rb"

# Generate a digest of the Rubinius runtime files
signature_file = "kernel/signature.rb"

compiler_files = FileList[
"lib/compiler.rb",
"lib/compiler/**/*.rb",
Expand All @@ -124,16 +127,25 @@ parser_files = FileList[
"lib/ext/melbourne/lex.c.blt"
]

kernel_files = FileList[
"kernel/**/*.txt",
"kernel/**/*.rb"
].exclude(signature_file)

config_files = FileList[
"Rakefile",
"config.rb",
"rakelib/*.rb",
"rakelib/*.rake"
]

# Generate a sha1 of all parser and compiler files to use as
# as signature in the .rbc files.
compiler_signature = "kernel/signature.rb"
signature_files = compiler_files + parser_files + kernel_files + config_files

file compiler_signature => compiler_files + parser_files do |t|
file signature_file => signature_files do
require 'digest/sha1'
digest = Digest::SHA1.new

(compiler_files + parser_files).each do |name|
signature_files.each do |name|
File.open name, "r" do |file|
while chunk = file.read(1024)
digest << chunk
Expand All @@ -143,13 +155,21 @@ file compiler_signature => compiler_files + parser_files do |t|

# Collapse the digest to a 64bit quantity
hd = digest.hexdigest
signature_hash = hd[0, 16].to_i(16) ^ hd[16,16].to_i(16) ^ hd[32,8].to_i(16)
SIGNATURE_HASH = hd[0, 16].to_i(16) ^ hd[16,16].to_i(16) ^ hd[32,8].to_i(16)

File.open compiler_signature, "wb" do |file|
File.open signature_file, "wb" do |file|
file.puts "# This file is generated by rakelib/kernel.rake. The signature"
file.puts "# is used to ensure that only current .rbc files are loaded."
file.puts "# is used to ensure that the runtime files and VM are in sync."
file.puts "#"
file.puts "Rubinius::Signature = #{signature_hash}"
file.puts "Rubinius::Signature = #{SIGNATURE_HASH}"
end
end

SIGNATURE_HEADER = "vm/gen/signature.h"

file SIGNATURE_HEADER => signature_file do |t|
File.open t.name, "wb" do |file|
file.puts "#define RBX_SIGNATURE #{SIGNATURE_HASH}ULL"
end
end

Expand All @@ -168,7 +188,7 @@ BUILD_CONFIG[:version_list].each do |ver|
end

signature = "runtime/#{ver}/signature"
file signature => compiler_signature do |t|
file signature => signature_file do |t|
File.open t.name, "wb" do |file|
puts "GEN #{t.name}"
file.puts Rubinius::Signature
Expand Down Expand Up @@ -196,23 +216,23 @@ BUILD_CONFIG[:version_list].each do |ver|
IO.foreach kernel_load_order do |name|
rbc = runtime_dir + name.chomp!
rb = kernel_dir + name.chop
kernel_file_task runtime, compiler_signature, ver, rb, rbc
kernel_file_task runtime, signature_file, ver, rb, rbc
end
end

[ compiler_signature,
[ signature_file,
"kernel/alpha.rb",
"kernel/loader.rb"
].each do |name|
kernel_file_task runtime, compiler_signature, ver, name
kernel_file_task runtime, signature_file, ver, name
end

compiler_files.map { |f| File.dirname f }.uniq.each do |dir|
directory dir
end

compiler_files.each do |name|
compiler_file_task runtime, compiler_signature, ver, name
compiler_file_task runtime, signature_file, ver, name
end
end

Expand All @@ -239,7 +259,7 @@ namespace :compiler do
require signature_path
end

task :generate => [compiler_signature]
task :generate => [signature_file]
end

desc "Build all kernel files (alias for kernel:build)"
Expand Down
1 change: 1 addition & 0 deletions rakelib/vm.rake
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ GENERATED = %W[ vm/gen/revision.h
vm/gen/config_variables.h
#{encoding_database}
#{transcoders_database}
#{SIGNATURE_HEADER}
] + TYPE_GEN + INSN_GEN

# Files are in order based on dependencies. For example,
Expand Down
1 change: 1 addition & 0 deletions vm/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define RBX_CONFIG

#include "gen/config.h"
#include "gen/signature.h"
#include "detection.hpp"

#endif
60 changes: 41 additions & 19 deletions vm/environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,21 +654,6 @@ namespace rubinius {
throw std::runtime_error(error);
}

// Pull in the signature file; this helps control when .rbc files need to
// be discarded and recompiled due to changes to the compiler since the
// .rbc files were created.
std::string sig_path = root + "/signature";
std::ifstream sig_stream(sig_path.c_str());
if(sig_stream) {
sig_stream >> signature_;
G(rubinius)->set_const(state, "Signature",
Integer::from(state, signature_));
sig_stream.close();
} else {
std::string error = "Unable to load compiler signature file: " + sig_path;
throw std::runtime_error(error);
}

version_ = as<Fixnum>(G(rubinius)->get_const(
state, state->symbol("RUBY_LIB_VERSION")))->to_native();

Expand Down Expand Up @@ -767,12 +752,47 @@ namespace rubinius {
return argv_[0];
}

static bool verify_and_set_paths(STATE, std::string prefix) {
bool Environment::load_signature(std::string runtime) {
std::string path = runtime;

// TODO: Fix this
if(LANGUAGE_20_ENABLED(state)) {
path += "/20";
} else if(LANGUAGE_19_ENABLED(state)) {
path += "/19";
} else {
path += "/18";
}

path += "/signature";

std::ifstream signature(path.c_str());
if(signature) {
signature >> signature_;

if(signature_ != RBX_SIGNATURE) return false;

signature.close();

return true;
}

/*
} else {
std::string error = "Unable to load compiler signature file: " + sig_path;
throw std::runtime_error(error);
*/
return false;
}

bool Environment::verify_paths(std::string prefix) {
struct stat st;

std::string dir = prefix + RBX_RUNTIME_PATH;
if(stat(dir.c_str(), &st) == -1 || !S_ISDIR(st.st_mode)) return false;

if(!load_signature(dir)) return false;

dir = prefix + RBX_BIN_PATH;
if(stat(dir.c_str(), &st) == -1 || !S_ISDIR(st.st_mode)) return false;

Expand All @@ -790,14 +810,14 @@ namespace rubinius {

// 1. Check if our configure prefix is overridden by the environment.
const char* path = getenv("RBX_PREFIX_PATH");
if(path && verify_and_set_paths(state, path)) {
if(path && verify_paths(path)) {
system_prefix_ = path;
return path;
}

// 2. Check if our configure prefix is valid.
path = RBX_PREFIX_PATH;
if(verify_and_set_paths(state, path)) {
if(verify_paths(path)) {
system_prefix_ = path;
return path;
}
Expand All @@ -809,7 +829,7 @@ namespace rubinius {

if(exe != std::string::npos) {
std::string prefix = name.substr(0, exe - strlen(RBX_BIN_PATH));
if(verify_and_set_paths(state, prefix)) {
if(verify_paths(prefix)) {
system_prefix_ = prefix;
return prefix;
}
Expand Down Expand Up @@ -838,6 +858,8 @@ namespace rubinius {

load_tool();

G(rubinius)->set_const(state, "Signature", Integer::from(state, signature_));

if(LANGUAGE_20_ENABLED(state)) {
runtime += "/20";
} else if(LANGUAGE_19_ENABLED(state)) {
Expand Down
9 changes: 6 additions & 3 deletions vm/environment.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ namespace rubinius {
int argc_;
char** argv_;

/// Signature to be used to verify the validity of .rbc files.
/// If the signature in a .rbc file does not match this value, the file
/// needs to be recompiled.
/**
* Digest of the runtime and configuration files to keep the runtime
* and VM in sync.
*/
uint64_t signature_;

// The Ruby library version with which the .rbc file is compatible.
Expand Down Expand Up @@ -88,6 +89,8 @@ namespace rubinius {

std::string executable_name();
std::string system_prefix();
bool verify_paths(std::string prefix);
bool load_signature(std::string dir);
void load_vm_options(int argc, char** argv);
void load_argv(int argc, char** argv);
void load_kernel(std::string root);
Expand Down

0 comments on commit 3ce0d8a

Please sign in to comment.