Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rubinius/rubinius
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 755dc4bfccab
Choose a base ref
...
head repository: rubinius/rubinius
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 288636defc93
Choose a head ref
  • 2 commits
  • 24 files changed
  • 1 contributor

Commits on Mar 31, 2016

  1. Some Arguments tweaks.

    brixen committed Mar 31, 2016
    Copy the full SHA
    e9943f7 View commit details
  2. Fixed issues with concurrent marking.

    As noted in one of the comments in this commit, there is a serious issue with
    partially initialized data when we have a concurrent marking thread running.
    When a Tuple is created, but the fields are not initialized to nil, they may
    contain random data.
    
    When a value is stored into a managed object, we run a write barrier. This bit
    of code serves two functions. First, it "remembers" the object being stored in
    case the object it is being stored into is a mature object and the object
    being stored is a young object. When the young collector runs, those
    "remembered" objects are part of the roots for the young region being
    collected. Second, if the object being stored into hasn't been traced yet, we
    trace it, and we add the object being stored to the stack of objects to trace.
    
    If the Tuple fields aren't initialized, we'll hit a garbage value when we try
    to trace it. If we don't run the write barrier when we assign values, we have
    the chance of losing one of those references. An alternative to "doubly
    initializing" the Tuple instance is to run two loops. One that assigns values
    and one that runs the write barrier on the entries. It should be apparent that
    we haven't really saved anything by using this purported "optimization" of
    creating the Tuple uninitialized (dirty).
    
    This is a good lesson in optimizing. The best optimization is not running any
    code at all, rather than making running code faster, if that is an option. It
    usually will give greater return to rework code in a way that significant code
    can be eliminated vs "optimized". In this case, we should get rid of Array and
    Tuple in the middle of stuff like calling methods.
    brixen committed Mar 31, 2016
    Copy the full SHA
    288636d View commit details
15 changes: 5 additions & 10 deletions machine/arguments.cpp
Original file line number Diff line number Diff line change
@@ -7,8 +7,7 @@

namespace rubinius {
void Arguments::append(STATE, Array* ary) {
Tuple* tup =
state->memory()->new_fields<Tuple>(state, G(tuple), ary->size() + total());
Tuple* tup = Tuple::create(state, ary->size() + total());

for(uint32_t i = 0; i < total(); i++) {
tup->put(state, i, get_argument(i));
@@ -23,8 +22,7 @@ namespace rubinius {
}

void Arguments::prepend(STATE, Array* ary) {
Tuple* tup =
state->memory()->new_fields<Tuple>(state, G(tuple), ary->size() + total());
Tuple* tup = Tuple::create(state, ary->size() + total());

for(native_int i = 0; i < ary->size(); i++) {
tup->put(state, i, ary->get(state, i));
@@ -49,8 +47,7 @@ namespace rubinius {
}

void Arguments::unshift(STATE, Object* val) {
Tuple* tup =
state->memory()->new_fields<Tuple>(state, G(tuple), total() + 1);
Tuple* tup = Tuple::create(state, total() + 1);

tup->put(state, 0, val);

@@ -62,8 +59,7 @@ namespace rubinius {
}

void Arguments::unshift2(STATE, Object* one, Object* two) {
Tuple* tup =
state->memory()->new_fields<Tuple>(state, G(tuple), total() + 2);
Tuple* tup = Tuple::create(state, total() + 2);

tup->put(state, 0, one);
tup->put(state, 1, two);
@@ -79,8 +75,7 @@ namespace rubinius {
Object* first = arguments_[0];

if(argument_container_) {
Tuple* tup =
state->memory()->new_fields<Tuple>(state, G(tuple), total() - 1);
Tuple* tup = Tuple::create(state, total() - 1);

for(uint32_t i = 1; i < total_; i++) {
tup->put(state, i - 1, get_argument(i));
26 changes: 26 additions & 0 deletions machine/arguments.hpp
Original file line number Diff line number Diff line change
@@ -49,6 +49,24 @@ namespace rubinius {
, argument_container_(0)
{}

Arguments(Symbol* name, Object* recv, Object* block)
: name_(name)
, recv_(recv)
, block_(block)
, total_(0)
, arguments_(0)
, argument_container_(0)
{}

Arguments(Symbol* name, Object* recv)
: name_(name)
, recv_(recv)
, block_(cNil)
, total_(0)
, arguments_(0)
, argument_container_(0)
{}

Arguments(Symbol* name)
: name_(name)
, recv_(cNil)
@@ -58,6 +76,14 @@ namespace rubinius {
, argument_container_(0)
{}

Arguments(Symbol* name, Object* recv, Object* block, Array* ary)
: name_(name)
, recv_(recv)
, block_(block)
{
use_array(ary);
}

Arguments(Symbol* name, Object* recv, Array* ary)
: name_(name)
, recv_(recv)
56 changes: 16 additions & 40 deletions machine/builtin/array.cpp
Original file line number Diff line number Diff line change
@@ -35,26 +35,7 @@ namespace rubinius {

Array* Array::create(STATE, native_int size) {
Array* ary = state->memory()->new_object<Array>(state, G(array));
Tuple* tup = Tuple::create(state, size);

if(ary->young_object_p()) {
ary->tuple(tup);
} else {
ary->tuple(state, tup);
}

return ary;
}

Array* Array::create_dirty(STATE, native_int size) {
Array* ary = state->memory()->new_object<Array>(state, G(array));
Tuple* tup = state->memory()->new_fields<Tuple>(state, G(tuple), size);

if(ary->young_object_p()) {
ary->tuple(tup);
} else {
ary->tuple(state, tup);
}
ary->tuple(state, Tuple::create(state, size));

return ary;
}
@@ -91,22 +72,21 @@ namespace rubinius {
} else {
ary->total(state, count);

Tuple* tup = state->memory()->new_fields<Tuple>(state, G(tuple), total);

if(tup->young_object_p()) {
for(native_int i = 0, j = start->to_native(); i < total; i++, j++) {
tup->field[i] = tuple()->field[j];
}
} else {
for(native_int i = 0, j = start->to_native(); i < total; i++, j++) {
tup->put(state, i, tuple()->field[j]);
}
}
/* We must use Tuple::create here and not new_fields<Tuple>, or we must
* do two passes, first setting all the fields and second running the
* write_barrier on each entry. The reason is that running the
* write_barrier via a 'tup->put(state, i, val)' will cause tup to be
* scanned when the concurrent marker is running, and it will hit
* garbage fields. If we don't run the write_barrier on every entry, we
* risk losing track of one. Note that the bugs described here will
* happen infrequently depending on the concurrent marker racing the
* mutator.
*/
Tuple* tup = Tuple::create(state, total);
ary->tuple(state, tup);

if(ary->young_object_p()) {
ary->tuple(tup);
} else {
ary->tuple(state, tup);
for(native_int i = 0, j = start->to_native(); i < total; i++, j++) {
tup->put(state, i, tuple()->field[j]);
}
}

@@ -231,11 +211,7 @@ namespace rubinius {
nt->field[i] = cNil;
}

if(young_object_p()) {
tuple(nt);
} else {
tuple(state, nt);
}
tuple(state, nt);

start(Fixnum::from(0));
}
1 change: 0 additions & 1 deletion machine/builtin/array.hpp
Original file line number Diff line number Diff line change
@@ -31,7 +31,6 @@ namespace rubinius {
}

static Array* create(STATE, native_int size);
static Array* create_dirty(STATE, native_int size);
static Array* from_tuple(STATE, Tuple* tup);
static Array* to_ary(STATE, Object* obj);

2 changes: 1 addition & 1 deletion machine/builtin/compiled_code.cpp
Original file line number Diff line number Diff line change
@@ -420,7 +420,7 @@ namespace rubinius {
Object* CompiledCode::execute_script(STATE) {
state->thread_state()->clear();

Arguments args(state->symbol("script"), G(main), 0, 0);
Arguments args(state->symbol("script"), G(main));

scope(state, ConstantScope::create(state));
scope()->module(state, G(object));
10 changes: 3 additions & 7 deletions machine/builtin/encoding.cpp
Original file line number Diff line number Diff line change
@@ -120,17 +120,13 @@ namespace rubinius {
}

static Tuple* encoding_reference(STATE, int index, const char* alias_name = 0) {
Tuple* pair = state->memory()->new_fields<Tuple>(state, G(tuple), 2);
Tuple* pair = Tuple::create(state, 2);

if(!alias_name) {
pair->put(state, 0, cNil);
} else {
if(alias_name) {
pair->put(state, 0, String::create(state, alias_name));
}

if(index < 0) {
pair->put(state, 1, cNil);
} else {
if(index >= 0) {
pair->put(state, 1, Fixnum::from(index));
}

5 changes: 1 addition & 4 deletions machine/builtin/executable.cpp
Original file line number Diff line number Diff line change
@@ -42,10 +42,7 @@ namespace rubinius {
Object* Executable::invoke(STATE, Symbol* name, Module* mod, Object* recv, Array* ary,
Object* block)
{
Arguments args(name, recv, 0, 0);
args.use_array(ary);
args.set_block(block);

Arguments args(name, recv, block, ary);
return execute(state, this, mod, args);
}

11 changes: 5 additions & 6 deletions machine/builtin/float.cpp
Original file line number Diff line number Diff line change
@@ -434,12 +434,11 @@ namespace rubinius {
char buf[FLOAT_TO_S_STRLEN];

int length = double_to_ascii(buf, FLOAT_TO_S_STRLEN, value(), &sign, &decpt);
Tuple* result = state->memory()->new_fields<Tuple>(state, G(tuple), 4);

result->put(state, 0, String::create(state, buf, length));
result->put(state, 1, Fixnum::from(decpt));
result->put(state, 2, Fixnum::from(sign));
result->put(state, 3, Fixnum::from(length));
Tuple* result = Tuple::from(state, 4,
String::create(state, buf, length),
Fixnum::from(decpt),
Fixnum::from(sign),
Fixnum::from(length));

return result;
}
8 changes: 2 additions & 6 deletions machine/builtin/object.cpp
Original file line number Diff line number Diff line change
@@ -514,9 +514,7 @@ namespace rubinius {
allow_private ? G(sym_private) : G(sym_protected));
Dispatch dispatch(name);

Arguments args(name, ary);
args.set_block(block);
args.set_recv(this);
Arguments args(name, this, block, ary);

return dispatch.send(state, lookup, args);
}
@@ -526,9 +524,7 @@ namespace rubinius {
allow_private ? G(sym_private) : G(sym_protected));
Dispatch dispatch(name);

Arguments args(name);
args.set_block(cNil);
args.set_recv(this);
Arguments args(name, this);

return dispatch.send(state, lookup, args);
}
3 changes: 1 addition & 2 deletions machine/builtin/regexp.cpp
Original file line number Diff line number Diff line change
@@ -336,8 +336,7 @@ namespace rubinius {
}

static Tuple* _md_region_to_tuple(STATE, OnigRegion *region, int pos) {
Tuple* tup =
state->memory()->new_fields<Tuple>(state, G(tuple), region->num_regs - 1);
Tuple* tup = Tuple::create(state, region->num_regs - 1);

for(int i = 1; i < region->num_regs; i++) {
int beg = region->beg[i];
2 changes: 1 addition & 1 deletion machine/builtin/system.cpp
Original file line number Diff line number Diff line change
@@ -1762,7 +1762,7 @@ namespace rubinius {

Tuple* System::vm_thread_state(STATE) {
VMThreadState* ts = state->vm()->thread_state();
Tuple* tuple = state->memory()->new_fields<Tuple>(state, G(tuple), 5);
Tuple* tuple = Tuple::create(state, 5);

Symbol* reason = 0;
switch(ts->raise_reason()) {
2 changes: 2 additions & 0 deletions machine/builtin/thread.cpp
Original file line number Diff line number Diff line change
@@ -147,6 +147,7 @@ namespace rubinius {

Thread* Thread::s_new(STATE, Object* self, Array* args, Object* block) {
Thread* thread = Thread::create(state, self, run_instance);
OnStack<1> os(state, thread);

CallFrame* call_frame = state->vm()->get_ruby_frame(1);

@@ -167,6 +168,7 @@ namespace rubinius {

Thread* Thread::s_start(STATE, Object* self, Array* args, Object* block) {
Thread* thread = Thread::create(state, self, run_instance);
OnStack<1> os(state, thread);

CallFrame* call_frame = state->vm()->get_ruby_frame(1);

18 changes: 3 additions & 15 deletions machine/builtin/tuple.cpp
Original file line number Diff line number Diff line change
@@ -88,8 +88,8 @@ namespace rubinius {
}

Tuple* Tuple::from(STATE, native_int fields, ...) {
Tuple* tup = Tuple::create(state, fields);
va_list ar;
Tuple* tup = state->memory()->new_fields<Tuple>(state, G(tuple), fields);

va_start(ar, fields);
for(native_int i = 0; i < fields; i++) {
@@ -279,28 +279,16 @@ namespace rubinius {
tuple->field[i] = val;
}

if(!tuple->young_object_p()) {
state->memory()->write_barrier(tuple, val);
}
state->memory()->write_barrier(tuple, val);

return tuple;
}

Tuple* Tuple::tuple_dup(STATE) {
native_int fields = num_fields();

Tuple* tup = state->memory()->new_fields<Tuple>(state, G(tuple), fields);

if(likely(tup->young_object_p())) {
// We have a young object so stores don't need the write barrier
for(native_int i = 0; i < fields; i++) {
tup->field[i] = field[i];
}

return tup;
}
Tuple* tup = Tuple::create(state, fields);

// Otherwise, we have a mature object
for(native_int i = 0; i < fields; i++) {
tup->put(state, i, field[i]);
}
1 change: 0 additions & 1 deletion machine/builtin/tuple.hpp
Original file line number Diff line number Diff line change
@@ -33,7 +33,6 @@ namespace rubinius {
}

static Tuple* create(STATE, native_int fields);
static Tuple* create_dirty(STATE, native_int fields);
static Tuple* from(STATE, native_int fields, ...);

/** Shift all elements leftward, clear old slots. */
27 changes: 7 additions & 20 deletions machine/builtin/variable_scope.cpp
Original file line number Diff line number Diff line change
@@ -70,16 +70,10 @@ namespace rubinius {
}

Tuple* VariableScope::local_variables(STATE) {
Tuple* tup = state->memory()->new_fields<Tuple>(state, G(tuple), number_of_locals());
Tuple* tup = Tuple::create(state, number_of_locals());

if(tup->young_object_p()) {
for(int i = 0; i < number_of_locals(); i++) {
tup->field[i] = get_local(state, i);
}
} else {
for(int i = 0; i < number_of_locals(); i++) {
tup->put(state, i, get_local(state, i));
}
for(int i = 0; i < number_of_locals(); i++) {
tup->put(state, i, get_local(state, i));
}

return tup;
@@ -191,18 +185,11 @@ namespace rubinius {
void VariableScope::flush_to_heap_internal(STATE) {
if(isolated()) return;

Tuple* new_locals =
state->memory()->new_fields<Tuple>(state, G(tuple), number_of_locals());
Tuple* new_locals = Tuple::create(state, number_of_locals());

if(new_locals->young_object_p()) {
for(int i = 0; i < number_of_locals(); i++) {
new_locals->field[i] = locals()[i];
}
} else {
for(int i = 0; i < number_of_locals(); i++) {
new_locals->put(state, i, locals()[i]);
}
}
for(int i = 0; i < number_of_locals(); i++) {
new_locals->put(state, i, locals()[i]);
}

heap_locals(state, new_locals);
isolated(1);
2 changes: 1 addition & 1 deletion machine/compiled_file.cpp
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ namespace rubinius {

state->thread_state()->clear();

Arguments args(state->symbol("script"), G(main), 0, 0);
Arguments args(state->symbol("script"), G(main));

code.get()->scope(state, ConstantScope::create(state));
code.get()->scope()->module(state, G(object));
Loading