Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into profiler
Browse files Browse the repository at this point in the history
brixen committed Apr 30, 2016

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 90db74d + 0b306fb commit 6dc84fb
Showing 31 changed files with 318 additions and 294 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ GEM
daedalus-core (0.5.0)
rake (10.5.0)
redcard (1.1.0)
rubinius-ast (3.4)
rubinius-ast (3.5)
rubinius-bridge (2.2)
redcard (~> 1.0)
rubinius-code (3.0)
5 changes: 0 additions & 5 deletions core/rubinius.rb
Original file line number Diff line number Diff line change
@@ -219,11 +219,6 @@ def self.thread_state
raise PrimitiveFailure, "Rubinius.thread_state primitive failed"
end

def self.check_interrupts
Rubinius.primitive :vm_check_interrupts
raise PrimitiveFailure, "Rubinius.check_interrupts primitive failed"
end

# Used to invoke a CompiledCode instance as a script body. Sets up the MAIN
# object as self and bypasses JIT'ing (because why JIT a script you only run
# once).
2 changes: 1 addition & 1 deletion gems_list.txt
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ rake-10.5.0.gem
rb-readline-0.5.3.gem
rdoc-4.2.2.gem
redcard-1.1.0.gem
rubinius-ast-3.4.gem
rubinius-ast-3.5.gem
rubinius-bridge-2.2.gem
rubinius-code-3.0.gem
rubinius-compiler-3.3.gem
14 changes: 7 additions & 7 deletions machine/builtin/block_environment.cpp
Original file line number Diff line number Diff line change
@@ -444,17 +444,17 @@ namespace rubinius {
call_frame->flags = invocation.flags | CallFrame::cMultipleScopes
| CallFrame::cBlock;

state->vm()->push_call_frame(call_frame, previous_frame);
if(!state->vm()->push_call_frame(state, call_frame, previous_frame)) {
return NULL;
}

Object* value = NULL;

// Check the stack and interrupts here rather than in the interpreter
// loop itself.
if(state->check_interrupts(state)) {
value = (*mcode->run)(state, mcode);
}
value = (*mcode->run)(state, mcode);

state->vm()->pop_call_frame(previous_frame);
if(!state->vm()->pop_call_frame(state, previous_frame)) {
return NULL;
}

return value;
}
6 changes: 3 additions & 3 deletions machine/builtin/channel.cpp
Original file line number Diff line number Diff line change
@@ -134,7 +134,7 @@ namespace rubinius {
ts.tv_nsec = nano % NANOSECONDS;
}

if(!state->check_async(state)) {
if(state->vm()->thread_interrupted_p(state)) {
return NULL;
}

@@ -161,7 +161,7 @@ namespace rubinius {

// or there are values available.
if(self->semaphore_count() > 0 || !self->value()->empty_p()) break;
if(!state->check_async(state)) {
if(state->vm()->thread_interrupted_p(state)) {
exception = true;
break;
}
@@ -173,7 +173,7 @@ namespace rubinius {
self->unpin();
self->_waiters_--;

if(exception || !state->check_async(state)) return NULL;
if(exception) return NULL;

if(self->semaphore_count() > 0) {
self->dec_semaphore_count();
9 changes: 7 additions & 2 deletions machine/builtin/fiber.cpp
Original file line number Diff line number Diff line change
@@ -98,7 +98,7 @@ namespace rubinius {

// TODO: CallFrame: return from this function

assert(0 && "fatal start_on_stack error");
rubinius::bug("returning from Fiber::start_on_stack");
#else
rubinius::bug("Fibers not supported on this platform");
#endif
@@ -155,10 +155,15 @@ namespace rubinius {

cur = Fiber::current(state);

// TODO: clean up this and the following conditional.
if(state->vm()->thread_interrupted_p(state)) {
return NULL;
}

if(!cur->exception()->nil_p()) {
state->raise_exception(cur->exception());
cur->exception(state, nil<Exception>());
return 0;
return NULL;
}

Array* ret = cur->value();
8 changes: 2 additions & 6 deletions machine/builtin/fiber.hpp
Original file line number Diff line number Diff line change
@@ -69,16 +69,12 @@ namespace rubinius {
return data()->machine();
}

void* stack_region() const {
return data()->stack_address();
}

void* stack_end() const {
void* stack_address() const {
return data()->stack_address();
}

void* stack_start() const {
return (void*)((uintptr_t)stack_region() + stack_size());
return (void*)((uintptr_t)stack_address() + stack_size());
}

int stack_size() const {
10 changes: 5 additions & 5 deletions machine/builtin/io.cpp
Original file line number Diff line number Diff line change
@@ -288,7 +288,7 @@ namespace rubinius {

if(events == -1) {
if(errno == EAGAIN || errno == EINTR) {
if(!state->check_async(state)) return NULL;
if(state->vm()->thread_interrupted_p(state)) return NULL;

// Recalculate the limit and go again.
if(maybe_limit) {
@@ -678,7 +678,7 @@ namespace rubinius {

if(bytes_read == -1) {
if(errno == EAGAIN || errno == EINTR) {
if(!state->check_async(state)) {
if(state->vm()->thread_interrupted_p(state)) {
if(malloc_buf) free(malloc_buf);
return NULL;
}
@@ -967,7 +967,7 @@ namespace rubinius {

if(bytes_read == -1) {
if(errno == EINTR) {
if(!state->check_async(state)) return NULL;
if(state->vm()->thread_interrupted_p(state)) return NULL;
ensure_open(state);
goto retry;
} else {
@@ -1321,7 +1321,7 @@ namespace rubinius {

if(code == -1) {
if(errno == EAGAIN || errno == EINTR) {
if(!state->check_async(state)) return NULL;
if(state->vm()->thread_interrupted_p(state)) return NULL;
ensure_open(state);
goto retry;
}
@@ -1429,7 +1429,7 @@ namespace rubinius {
break;
case EAGAIN:
case EINTR:
if(!state->check_async(state)) return NULL;
if(state->vm()->thread_interrupted_p(state)) return NULL;
io->ensure_open(state);
goto retry;
default:
10 changes: 1 addition & 9 deletions machine/builtin/native_function.cpp
Original file line number Diff line number Diff line change
@@ -308,8 +308,6 @@ namespace rubinius {
FFIData* stub = reinterpret_cast<FFIData*>(user_data);

bool destroy_vm = false;
int stack_address = 0;

if(!env) {
// TODO: fix this, the threads should *always* be set up correctly
// Apparently we're running in a new thread here, setup
@@ -318,13 +316,7 @@ namespace rubinius {

VM* vm = stub->shared->thread_nexus()->new_vm(stub->shared, "ruby.ffi");

// Detect the stack size and set it up in the VM object
size_t stack_size;
pthread_attr_t attrs;
pthread_attr_init(&attrs);
pthread_attr_getstacksize (&attrs, &stack_size);
pthread_attr_destroy(&attrs);
vm->set_root_stack(reinterpret_cast<uintptr_t>(&stack_address), stack_size);
vm->set_stack_bounds(THREAD_STACK_SIZE);

// Setup nativemethod handles into thread local
State state(vm);
15 changes: 8 additions & 7 deletions machine/builtin/native_method.cpp
Original file line number Diff line number Diff line change
@@ -675,7 +675,9 @@ namespace rubinius {
env->set_current_native_frame(&nmf);

// Register the CallFrame, because we might GC below this.
state->vm()->push_call_frame(call_frame, previous_frame);
if(!state->vm()->push_call_frame(state, call_frame, previous_frame)) {
return NULL;
}

// Be sure to do this after installing nmf as the current
// native frame.
@@ -706,7 +708,7 @@ namespace rubinius {
} catch(const RubyException& exc) {
LEAVE_CAPI(state);

state->vm()->pop_call_frame(previous_frame);
state->vm()->pop_call_frame(state, previous_frame);
env->set_current_call_frame(saved_frame);
env->set_current_native_frame(nmf.previous());
ep.pop(env);
@@ -716,15 +718,14 @@ namespace rubinius {

LEAVE_CAPI(state);

state->vm()->pop_call_frame(previous_frame);
if(!state->vm()->pop_call_frame(state, previous_frame)) {
value = NULL;
}

env->set_current_call_frame(saved_frame);
env->set_current_native_frame(nmf.previous());
ep.pop(env);

// Handle any signals that occurred while the native method
// was running.
if(!state->check_async(state)) return NULL;

return value;
}

14 changes: 3 additions & 11 deletions machine/builtin/system.cpp
Original file line number Diff line number Diff line change
@@ -656,7 +656,7 @@ namespace rubinius {
switch(errno) {
case EAGAIN:
case EINTR:
if(!state->check_async(state)) {
if(state->vm()->thread_interrupted_p(state)) {
close(output[0]);
return NULL;
}
@@ -782,7 +782,7 @@ namespace rubinius {
if(pid == -1) {
if(errno == ECHILD) return cFalse;
if(errno == EINTR) {
if(!state->check_async(state)) return NULL;
if(state->vm()->thread_interrupted_p(state)) return NULL;
goto retry;
}

@@ -1029,19 +1029,11 @@ namespace rubinius {
if(!state->park(state)) return NULL;
}

if(!state->check_async(state)) return NULL;
if(state->vm()->thread_interrupted_p(state)) return NULL;

return Fixnum::from(time(0) - start);
}

Object* System::vm_check_interrupts(STATE) {
if(state->check_async(state)) {
return cNil;
} else {
return NULL;
}
}

static inline double tv_to_dbl(struct timeval* tv) {
return (double)tv->tv_sec + ((double)tv->tv_usec / 1000000.0);
}
3 changes: 0 additions & 3 deletions machine/builtin/system.hpp
Original file line number Diff line number Diff line change
@@ -147,9 +147,6 @@ namespace rubinius {
// Rubinius.primitive :vm_sleep
static Object* vm_sleep(STATE, Object* duration);

// Rubinius.primitive :vm_check_interrupts
static Object* vm_check_interrupts(STATE);

// Rubinius.primitive :vm_times
static Array* vm_times(STATE);

4 changes: 1 addition & 3 deletions machine/builtin/thread.cpp
Original file line number Diff line number Diff line change
@@ -356,6 +356,7 @@ namespace rubinius {
VM* vm = reinterpret_cast<VM*>(ptr);
State state_obj(vm), *state = &state_obj;

vm->set_stack_bounds(THREAD_STACK_SIZE);
vm->set_current_thread();

RUBINIUS_THREAD_START(
@@ -367,9 +368,6 @@ namespace rubinius {
vm->name().c_str(), vm->thread->pid()->to_native(),
(unsigned int)thread_debug_self());

int stack_address = 0;
vm->set_root_stack(reinterpret_cast<uintptr_t>(&stack_address), THREAD_STACK_SIZE);

NativeMethod::init_thread(state);

state->vm()->become_managed();
20 changes: 10 additions & 10 deletions machine/capi/capi.cpp
Original file line number Diff line number Diff line change
@@ -51,14 +51,17 @@ namespace rubinius {
return map[type];
}

bool capi_check_interrupts(STATE, void* stack_marker) {
if(!state->check_stack(state, stack_marker)) {
bool capi_check_interrupts(STATE) {
void* stack_address;

if(!state->vm()->check_stack(state, &stack_address)) {
return false;
}

if(unlikely(state->check_local_interrupts())) {
if(!state->process_async(state)) return false;
if(unlikely(state->vm()->check_local_interrupts())) {
return state->vm()->check_thread_raise_or_kill(state);
}

return true;
}

@@ -115,8 +118,7 @@ namespace rubinius {
Object** args, Object* block,
bool allow_private)
{
int stack_marker = 0;
if(!capi_check_interrupts(env->state(), &stack_marker)) {
if(!capi_check_interrupts(env->state())) {
env->current_ep()->return_to(env);
}

@@ -208,8 +210,7 @@ namespace rubinius {
Object* blk,
size_t arg_count, Object** arg_vals)
{
int stack_marker = 0;
if(!capi_check_interrupts(env->state(), &stack_marker)) {
if(!capi_check_interrupts(env->state())) {
env->current_ep()->return_to(env);
}

@@ -258,8 +259,7 @@ namespace rubinius {
VALUE capi_call_super_native(NativeMethodEnvironment* env,
size_t arg_count, Object** args)
{
int stack_marker = 0;
if(!capi_check_interrupts(env->state(), &stack_marker)) {
if(!capi_check_interrupts(env->state())) {
env->current_ep()->return_to(env);
}

4 changes: 2 additions & 2 deletions machine/capi/thread.cpp
Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@ extern "C" {
ret = select(max, read, write, except, tvp);
}

bool ok = env->state()->check_async(env->state());
bool ok = !env->state()->vm()->thread_interrupted_p(env->state());

ENTER_CAPI(env->state());

@@ -199,7 +199,7 @@ extern "C" {
State* state = env->state();
void* ret = NULL;

if(!state->check_async(env->state())) {
if(state->vm()->thread_interrupted_p(state)) {
return ret;
}
if(ubf == RUBY_UBF_IO || ubf == RUBY_UBF_PROCESS) {
17 changes: 11 additions & 6 deletions machine/environment.cpp
Original file line number Diff line number Diff line change
@@ -59,6 +59,7 @@
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <pwd.h>
#include <dirent.h>

@@ -93,8 +94,6 @@ namespace rubinius {

String::init_hash();

VM::init_stack_size();

copy_argv(argc, argv);
ruby_init_setproctitle(argc, argv);

@@ -108,9 +107,14 @@ namespace rubinius {
root_vm->set_main_thread();
shared->set_root_vm(root_vm);

int stack_address = 0;
root_vm->set_root_stack(
reinterpret_cast<uintptr_t>(&stack_address), VM::cStackDepthMax);
size_t stack_size = THREAD_STACK_SIZE;
struct rlimit rlim;

if(getrlimit(RLIMIT_STACK, &rlim) == 0) {
stack_size = rlim.rlim_cur;
}

root_vm->set_stack_bounds(stack_size);
root_vm->set_current_thread();

state = new State(root_vm);
@@ -818,8 +822,9 @@ namespace rubinius {

// Start signal handling. We don't return until the process is exiting.
VM* vm = SignalThread::new_vm(state);
State main_state(vm);
vm->set_stack_bounds(state->vm()->stack_size());

State main_state(vm);
state->shared().start_signals(&main_state);
}
}
29 changes: 23 additions & 6 deletions machine/instructions.def
Original file line number Diff line number Diff line change
@@ -1766,8 +1766,6 @@ instruction check_interrupts() [ -- ]
mcode->call_count++;
}

if(!state->check_async(state)) RUN_EXCEPTION();

state->vm()->checkpoint(state);
end

@@ -1944,16 +1942,33 @@ instruction zsuper(literal) [ block -- value ]
}

Tuple* tup = Tuple::create(state, arg_count);
for(int i = 0; i < mc->total_args; i++) {
tup->put(state, i, scope->get_local(state, i));
native_int tup_index = 0;

native_int fixed_args;
if(splat) {
fixed_args = mc->splat_position;
} else if(mc->keywords) {
fixed_args = mc->total_args - 1;
} else {
fixed_args = mc->total_args;
}
for(native_int i = 0; i < fixed_args; i++) {
tup->put(state, tup_index++, scope->get_local(state, i));
}

if(splat) {
for(native_int i = 0; i < splat->size(); i++) {
tup->put(state, i + mc->total_args, splat->get(state, i));
tup->put(state, tup_index++, splat->get(state, i));
}
} else if(splat_obj) {
tup->put(state, mc->total_args, splat_obj);
tup->put(state, tup_index++, splat_obj);
}

if(mc->post_args) {
native_int post_position = mc->splat_position + 1;
for(native_int i = post_position; i < post_position + mc->post_args; i++) {
tup->put(state, tup_index++, scope->get_local(state, i));
}
}

if(mc->keywords) {
@@ -1969,6 +1984,8 @@ instruction zsuper(literal) [ block -- value ]

placeholder->send(state, state->symbol("[]="), ary);
}

tup->put(state, tup_index++, scope->get_local(state, placeholder_position));
}

CallSite* call_site = reinterpret_cast<CallSite*>(literal);
3 changes: 1 addition & 2 deletions machine/internal_threads.cpp
Original file line number Diff line number Diff line change
@@ -33,8 +33,7 @@ namespace rubinius {
RUBINIUS_THREAD_START(
const_cast<RBX_DTRACE_CHAR_P>(vm->name().c_str()), vm->thread_id(), 1);

int stack_address = 0;
vm->set_root_stack(reinterpret_cast<uintptr_t>(&stack_address), thread->stack_size_);
vm->set_stack_bounds(thread->stack_size_);

NativeMethod::init_thread(state);

18 changes: 4 additions & 14 deletions machine/jit/llvm/util.cpp
Original file line number Diff line number Diff line change
@@ -113,10 +113,10 @@ extern "C" {
call_frame->arguments = args;

CallFrame* previous;
state->vm()->push_call_frame(call_frame, previous);
return state->vm()->push_call_frame(state, call_frame, previous);
}

void rbx_block_frame_initialize(STATE,
bool rbx_block_frame_initialize(STATE,
CallFrame* call_frame, StackVariables* scope,
BlockEnvironment* env, Arguments* args, BlockInvocation* invocation)
{
@@ -153,11 +153,11 @@ extern "C" {
| CallFrame::cJITed;

CallFrame* previous;
state->vm()->push_call_frame(call_frame, previous);
return state->vm()->push_call_frame(state, call_frame, previous);
}

void rbx_pop_call_frame(STATE) {
state->vm()->pop_call_frame(state->vm()->call_frame()->previous);
state->vm()->pop_call_frame(state, state->vm()->call_frame()->previous);
}

Object* rbx_splat_send(STATE, CallSite* call_site,
@@ -985,20 +985,10 @@ extern "C" {
}

Object* rbx_prologue_check(STATE) {
if(!state->check_interrupts(state)) return NULL;

// TODO: ensure no stack references exist at this point
// state->vm()->checkpoint(state);

return cTrue;
}

Object* rbx_check_interrupts(STATE) {
if(!state->check_async(state)) return NULL;

// TODO: ensure no stack references exist at this point
// state->vm()->checkpoint(state);

return cTrue;
}

31 changes: 15 additions & 16 deletions machine/machine_code.cpp
Original file line number Diff line number Diff line change
@@ -762,7 +762,9 @@ namespace rubinius {
call_frame->scope = scope;
call_frame->arguments = &args;

state->vm()->push_call_frame(call_frame, previous_frame);
if(!state->vm()->push_call_frame(state, call_frame, previous_frame)) {
return NULL;
}

#ifdef ENABLE_LLVM
// A negative call_count means we've disabled usage based JIT
@@ -780,13 +782,13 @@ namespace rubinius {

Object* value = 0;

if(state->check_interrupts(state)) {
RUBINIUS_METHOD_ENTRY_HOOK(state, scope->module(), args.name());
value = (*mcode->run)(state, mcode);
RUBINIUS_METHOD_RETURN_HOOK(state, scope->module(), args.name());
}
RUBINIUS_METHOD_ENTRY_HOOK(state, scope->module(), args.name());
value = (*mcode->run)(state, mcode);
RUBINIUS_METHOD_RETURN_HOOK(state, scope->module(), args.name());

state->vm()->pop_call_frame(previous_frame);
if(!state->vm()->pop_call_frame(state, previous_frame)) {
return NULL;
}

return value;
}
@@ -825,14 +827,9 @@ namespace rubinius {
call_frame->scope = scope;
call_frame->arguments = &args;

state->vm()->push_call_frame(call_frame, previous_frame);

// Do NOT check if we should JIT this. We NEVER want to jit a script.

// Check the stack and interrupts here rather than in the interpreter
// loop itself.

if(!state->check_interrupts(state)) return NULL;
if(!state->vm()->push_call_frame(state, call_frame, previous_frame)) {
return NULL;
}

state->vm()->checkpoint(state);

@@ -841,7 +838,9 @@ namespace rubinius {

Object* value = (*mcode->run)(state, mcode);

state->vm()->pop_call_frame(previous_frame);
if(!state->vm()->pop_call_frame(state, previous_frame)) {
return NULL;
}

return value;
}
24 changes: 13 additions & 11 deletions machine/memory/finalizer.cpp
Original file line number Diff line number Diff line change
@@ -213,22 +213,24 @@ namespace memory {
env->set_current_native_frame(&nmf);

// Register the CallFrame, because we might GC below this.
state->vm()->push_call_frame(call_frame, previous_frame);
if(state->vm()->push_call_frame(state, call_frame, previous_frame)) {
nmf.setup(Qnil, Qnil, Qnil, Qnil);

nmf.setup(Qnil, Qnil, Qnil, Qnil);
PLACE_EXCEPTION_POINT(ep);

PLACE_EXCEPTION_POINT(ep);
if(unlikely(ep.jumped_to())) {
logger::warn(
"finalizer: an exception occurred running a NativeMethod finalizer");
} else {
(*process_item_->finalizer)(state, process_item_->object);
}

if(unlikely(ep.jumped_to())) {
logger::warn(
"finalizer: an exception occurred running a NativeMethod finalizer");
state->vm()->pop_call_frame(state, previous_frame);
env->set_current_call_frame(0);
env->set_current_native_frame(0);
} else {
(*process_item_->finalizer)(state, process_item_->object);
logger::warn("finalizer: stack error");
}

state->vm()->pop_call_frame(previous_frame);
env->set_current_call_frame(0);
env->set_current_native_frame(0);
}
}
process_item_->status = FinalizeObject::eNativeFinalized;
8 changes: 4 additions & 4 deletions machine/park.cpp
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@

namespace rubinius {
Object* Park::park(STATE) {
if(!state->check_async(state)) return NULL;
if(state->vm()->thread_interrupted_p(state)) return NULL;

utilities::thread::Mutex::LockGuard lg(mutex_);

@@ -25,7 +25,7 @@ namespace rubinius {
cond_.wait(mutex_);
}
mutex_.unlock();
if(!state->check_async(state)) {
if(state->vm()->thread_interrupted_p(state)) {
mutex_.lock();
result = NULL;
break;
@@ -40,7 +40,7 @@ namespace rubinius {

Object* Park::park_timed(STATE, struct timespec* ts) {
utilities::thread::Mutex::LockGuard lg(mutex_);
if(!state->check_async(state)) return NULL;
if(state->vm()->thread_interrupted_p(state)) return NULL;

wake_ = false;
sleeping_ = true;
@@ -59,7 +59,7 @@ namespace rubinius {
}
}
mutex_.unlock();
if(!state->check_async(state)) {
if(state->vm()->thread_interrupted_p(state)) {
mutex_.lock();
timeout = NULL;
break;
5 changes: 1 addition & 4 deletions machine/signal.cpp
Original file line number Diff line number Diff line change
@@ -165,15 +165,12 @@ namespace rubinius {

State state_obj(vm), *state = &state_obj;

vm->set_stack_bounds(THREAD_STACK_SIZE);
vm->set_current_thread();

RUBINIUS_THREAD_START(
const_cast<RBX_DTRACE_CHAR_P>(vm->name().c_str()), vm->thread_id(), 1);

int stack_address = 0;
vm->set_root_stack(
reinterpret_cast<uintptr_t>(&stack_address), SignalThread::stack_size);

NativeMethod::init_thread(state);

thread->run(state);
56 changes: 0 additions & 56 deletions machine/state.cpp
Original file line number Diff line number Diff line change
@@ -19,62 +19,6 @@ namespace rubinius {
vm_->thread_state()->raise_exception(exc);
}

bool State::process_async(STATE) {
utilities::thread::SpinLock::LockGuard guard(vm_->interrupt_lock());

vm_->clear_check_local_interrupts();

Exception* exc = vm_->interrupted_exception_.get();
if(!exc->nil_p()) {
vm_->interrupted_exception_.set(nil<Exception>());

// Only write the locations if there are none.
if(exc->locations()->nil_p() || exc->locations()->size() == 0) {
exc->locations(this, Location::from_call_stack(this));
}

vm_->thread_state_.raise_exception(exc);
return false;
}
if(vm_->interrupt_by_kill()) {
Fiber* fib = vm_->current_fiber.get();
if(fib->nil_p() || fib->root_p()) {
vm_->clear_interrupt_by_kill();
} else {
vm_->set_check_local_interrupts();
}
vm_->thread_state_.raise_thread_kill();
return false;
}

return true;
}

bool State::check_interrupts(STATE) {
// First, we might be here because someone reset the stack_limit_ so that
// we'd fall into here to check interrupts even if the stack is fine,
//
// So fix up the stack_limit_ if thats the case first.

// If this is true, stack_limit_ was just changed to get our attention, reset
// it now.
int stack_marker = 0;
if(!check_stack(state, &stack_marker)) return false;

if(unlikely(check_local_interrupts())) {
if(!process_async(state)) return false;
}

// If the current thread is trying to step, debugger wise, then assist!
if(vm_->thread_step()) {
vm_->clear_thread_step();
if(!Helpers::yield_debugger(this, cNil)) return false;
}

return true;
}


Object* State::park(STATE) {
return vm_->park_->park(this);
}
23 changes: 0 additions & 23 deletions machine/state.hpp
Original file line number Diff line number Diff line change
@@ -93,35 +93,12 @@ namespace rubinius {
return shared_;
}

bool detect_stack_condition(void* end) const {
return vm_->detect_stack_condition(end);
}

bool check_local_interrupts() const {
return vm_jit_->check_local_interrupts_;
}

bool check_async(STATE) {
if(vm_->check_local_interrupts()) {
return process_async(state);
}
return true;
}

void raise_stack_error(STATE);

bool check_stack(STATE, void* end) {
// @TODO assumes stack growth direction
if(unlikely(vm_->detect_stack_condition(end))) {
raise_stack_error(state);
return false;
}
return true;
}

bool process_async(STATE);
bool check_interrupts(STATE);

Object* park(STATE);
Object* park_timed(STATE, struct timespec* ts);
};
99 changes: 67 additions & 32 deletions machine/vm.cpp
Original file line number Diff line number Diff line change
@@ -57,25 +57,17 @@
#define GO(whatever) globals().whatever

namespace rubinius {

unsigned long VM::cStackDepthMax = 655300;

#ifndef RBX_WINDOWS
/**
* Maximum amount of stack space to use.
* getrlimit can report there is 4G of stack (ie, unlimited). Even when
* there is unlimited stack, we clamp the max to this value (currently 128M).
*/
static rlim_t cMaxStack = (1024 * 1024 * 128);
#endif

VM::VM(uint32_t id, SharedState& shared, const char* name)
: memory::ManagedThread(id, shared, memory::ManagedThread::eRuby, name)
, call_frame_(NULL)
, thread_nexus_(shared.thread_nexus())
, saved_call_site_information_(NULL)
, fiber_stacks_(this, shared)
, park_(new Park)
, stack_start_(0)
, stack_size_(0)
, current_stack_start_(0)
, current_stack_size_(0)
, interrupt_lock_()
, method_missing_reason_(eNone)
, constant_missing_reason_(vFound)
@@ -111,10 +103,66 @@ namespace rubinius {
delete vm;
}

void VM::push_call_frame(CallFrame* frame, CallFrame*& previous_frame) {
void VM::set_stack_bounds(size_t size) {
void* stack_address;

stack_size_ = size;
stack_start_ = &stack_address;

set_stack_bounds(stack_start_, stack_size_);
}

void VM::raise_stack_error(STATE) {
state->raise_stack_error(state);
}

bool VM::push_call_frame(STATE, CallFrame* frame, CallFrame*& previous_frame) {
if(!check_stack(state, frame)) return false;

previous_frame = call_frame_;
frame->previous = call_frame_;
call_frame_ = frame;

return true;
}

bool VM::check_thread_raise_or_kill(STATE) {
Exception* exc = interrupted_exception();

if(!exc->nil_p()) {
clear_interrupted_exception();

// Only write the locations if there are none.
if(exc->locations()->nil_p() || exc->locations()->size() == 0) {
exc->locations(this, Location::from_call_stack(state));
}

thread_state_.raise_exception(exc);

return true;
}

if(interrupt_by_kill()) {
Fiber* fib = current_fiber.get();

if(fib->nil_p() || fib->root_p()) {
clear_interrupt_by_kill();
} else {
set_check_local_interrupts();
}

thread_state_.raise_thread_kill();

return true;
}

// If the current thread is trying to step, debugger wise, then assist!
if(thread_step()) {
clear_thread_step();
if(!Helpers::yield_debugger(state, cNil)) return true;
}

return false;
}

CallFrame* VM::get_call_frame(ssize_t up) {
@@ -285,24 +333,6 @@ namespace rubinius {
}
}

void VM::init_stack_size() {
#ifndef RBX_WINDOWS
struct rlimit rlim;
if(getrlimit(RLIMIT_STACK, &rlim) == 0) {
rlim_t space = rlim.rlim_cur/5;

if(space > 1024*1024) space = 1024*1024;
rlim_t adjusted = (rlim.rlim_cur - space);

if(adjusted > cMaxStack) {
cStackDepthMax = cMaxStack;
} else {
cStackDepthMax = adjusted;
}
}
#endif
}

TypeInfo* VM::find_type(int type) {
return memory()->type_info[type];
}
@@ -467,7 +497,12 @@ namespace rubinius {
}

void VM::set_current_fiber(Fiber* fib) {
set_stack_bounds((uintptr_t)fib->stack_start(), fib->stack_size());
if(fib->root_p()) {
restore_stack_bounds();
} else {
set_stack_bounds(fib->stack_start(), fib->stack_size());
}

current_fiber.set(fib);
}

98 changes: 53 additions & 45 deletions machine/vm.hpp
Original file line number Diff line number Diff line change
@@ -101,8 +101,11 @@ namespace rubinius {
Park* park_;
rbxti::Env* tooling_env_;

uintptr_t root_stack_start_;
uintptr_t root_stack_size_;
void* stack_start_;
size_t stack_size_;

void* current_stack_start_;
size_t current_stack_size_;

utilities::thread::SpinLock interrupt_lock_;

@@ -142,8 +145,6 @@ namespace rubinius {

VMThreadState thread_state_;

static unsigned long cStackDepthMax;

public: /* Inline methods */

UnwindInfoSet& unwinds() {
@@ -206,13 +207,58 @@ namespace rubinius {
return shared.memory();
}

void push_call_frame(CallFrame* frame, CallFrame*& previous_frame);
void raise_stack_error(STATE);

size_t stack_size() {
return current_stack_size_;
}

void restore_stack_bounds() {
current_stack_start_ = stack_start_;
current_stack_size_ = stack_size_;
}

void set_stack_bounds(void* start, size_t size) {
current_stack_start_ = start;
current_stack_size_ = size;
}

void set_stack_bounds(size_t size);

bool check_stack(STATE, void* stack_address) {
ssize_t stack_used =
(reinterpret_cast<intptr_t>(current_stack_start_)
- reinterpret_cast<intptr_t>(stack_address));

void pop_call_frame(CallFrame* frame) {
if(stack_used < 0) stack_used = -stack_used;

if(stack_used > stack_size_) {
raise_stack_error(state);
return false;
}

return true;
}

bool push_call_frame(STATE, CallFrame* frame, CallFrame*& previous_frame);

bool pop_call_frame(STATE, CallFrame* frame) {
call_frame_ = frame;

return !thread_interrupted_p(state);
}

bool thread_interrupted_p(STATE) {
if(check_local_interrupts()) {
return check_thread_raise_or_kill(state);
}

return false;
}

// Do NOT de-deplicate
bool check_thread_raise_or_kill(STATE);

// Do NOT de-duplicate
void set_call_frame(CallFrame* frame) {
call_frame_ = frame;
}
@@ -244,42 +290,6 @@ namespace rubinius {
return shared.globals;
}

void* stack_start() const {
return reinterpret_cast<void*>(vm_jit_.stack_start_);
}

int stack_size() const {
return vm_jit_.stack_size_;
}

void reset_stack_limit() {
// @TODO assumes stack growth direction
vm_jit_.stack_limit_ = (vm_jit_.stack_start_ - vm_jit_.stack_size_) + (4096 * 10);
}

void set_stack_bounds(uintptr_t start, int length) {
if(start == 0) {
start = root_stack_start_;
length = root_stack_size_;
}

vm_jit_.stack_start_ = start;
vm_jit_.stack_size_ = length;
reset_stack_limit();
}

void set_root_stack(uintptr_t start, int length) {
root_stack_start_ = start;
root_stack_size_ = length;

set_stack_bounds(root_stack_start_, root_stack_size_);
}

bool detect_stack_condition(void* end) const {
// @TODO assumes stack growth direction
return reinterpret_cast<uintptr_t>(end) < vm_jit_.stack_limit_;
}

MethodMissingReason method_missing_reason() const {
return method_missing_reason_;
}
@@ -391,8 +401,6 @@ namespace rubinius {
memory::VariableRootBuffers& current_root_buffers();

public:
static void init_stack_size();

static VM* current();

static void discard(STATE, VM*);
37 changes: 37 additions & 0 deletions spec/core/callsite/reset_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require File.expand_path('../../fixtures/call_site.rb', __FILE__)

describe "Rubinius::CallSite#reset" do
before :each do
@klass = Class.new do
def m(a)
a.to_s
end
end

@call_site = @klass.instance_method(:m).executable.call_sites.first
end

it "clears the caches" do
obj = @klass.new

obj.m 1
obj.m :a

@call_site.depth.should == 1
@call_site.reset

@call_site.depth.should == 0
end

it "sets the invokes to 0" do
obj = @klass.new

obj.m 1
obj.m :a

@call_site.invokes.should == 2
@call_site.reset

@call_site.invokes.should == 0
end
end
16 changes: 16 additions & 0 deletions spec/ruby/language/block_spec.rb
Original file line number Diff line number Diff line change
@@ -196,6 +196,12 @@ def m(a) yield a end
var.should == 1
end

it "does not capture a local when the block argument has the same name" do
var = 1
proc { |&var| var[2] }[&proc { |x| x }].should == 2
var.should == 1
end

describe "taking zero arguments" do
it "does not raise an exception when no values are yielded" do
@y.z { 1 }.should == 1
@@ -704,6 +710,16 @@ def m(a) yield a end
glark.should be_nil
end
end

it "are visible in deeper scopes before initialization" do
[1].each {|;glark|
[1].each {
defined?(glark).should_not be_nil
glark = 1
}
glark.should == 1
}
end
end

describe "Post-args" do
14 changes: 14 additions & 0 deletions spec/ruby/language/fixtures/super.rb
Original file line number Diff line number Diff line change
@@ -347,4 +347,18 @@ def foo(a:, b: 'b', **)
end
end
end

module SplatAndKeyword
class A
def foo(*args, **options)
[args, options]
end
end

class B < A
def foo(*args, **options)
super
end
end
end
end
8 changes: 8 additions & 0 deletions spec/ruby/language/super_spec.rb
Original file line number Diff line number Diff line change
@@ -177,5 +177,13 @@ def a(arg)

b.foo.should == {}
end

describe 'when using splat arguments' do
it 'passes splat arguments and keyword arguments to the parent' do
b = Super::SplatAndKeyword::B.new

b.foo('bar', baz: true).should == [['bar'], {baz: true}]
end
end
end
end

0 comments on commit 6dc84fb

Please sign in to comment.