Skip to content

Commit

Permalink
Fixed guarding references when calling methods from the VM.
Browse files Browse the repository at this point in the history
  • Loading branch information
brixen committed Aug 30, 2015
1 parent e12ce1a commit 65b9bd1
Show file tree
Hide file tree
Showing 16 changed files with 252 additions and 173 deletions.
4 changes: 2 additions & 2 deletions vm/builtin/array.cpp
Expand Up @@ -3,6 +3,7 @@
#include "dispatch.hpp"
#include "object_utils.hpp"
#include "object_memory.hpp"
#include "on_stack.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
Expand Down Expand Up @@ -150,12 +151,11 @@ namespace rubinius {
Exception::type_error(state, "to_ary should return an Array", call_frame);
return 0;
}

// NOTE: On >= 1.9, if res is nil just fall through and return [value]
}

Array* ary = Array::create(state, 1);
ary->set(state, 0, value);

return ary;
}

Expand Down
26 changes: 14 additions & 12 deletions vm/builtin/autoload.cpp
Expand Up @@ -14,45 +14,47 @@ namespace rubinius {
return state->memory()->new_object<Autoload>(state, G(autoload));
}

Object* Autoload::resolve(STATE, CallFrame* call_frame, Module* under, bool honor_require) {
Object* Autoload::resolve(STATE, CallFrame* call_frame,
Module* under, bool honor_require)
{
Autoload* self = this;
OnStack<1> os(state, self);
Object* res = send(state, call_frame, state->symbol("resolve"));
OnStack<2> os(state, self, under);

Object* res = send(state, call_frame, state->symbol("resolve"));
if(!res) return NULL;

if(CBOOL(res) || !honor_require) {
ConstantMissingReason reason = vNonExistent;
Object* constant = Helpers::const_get_under(state, under, self->name(), &reason, self, true);
Object* constant = Helpers::const_get_under(
state, under, self->name(), &reason, self, true);

if(!constant) return NULL;
if(reason == vFound) return constant;

if(reason == vFound) {
return constant;
}
return Helpers::const_missing_under(state, under, self->name(), call_frame);
}

return cNil;
}

Object* Autoload::resolve(STATE, CallFrame* call_frame, bool honor_require) {
Autoload* self = this;
OnStack<1> os(state, self);
Object* res = send(state, call_frame, state->symbol("resolve"));

Object* res = send(state, call_frame, state->symbol("resolve"));
if(!res) return NULL;

if(CBOOL(res) || !honor_require) {
ConstantMissingReason reason = vNonExistent;
Object* constant = Helpers::const_get(state, call_frame, self->name(), &reason, self, true);
Object* constant = Helpers::const_get(
state, call_frame, self->name(), &reason, self, true);

if(!constant) return NULL;
if(reason == vFound) return constant;

if(reason == vFound) {
return constant;
}
return Helpers::const_missing(state, self->name(), call_frame);
}

return cNil;
}
}
25 changes: 20 additions & 5 deletions vm/builtin/block_environment.cpp
Expand Up @@ -220,8 +220,15 @@ namespace rubinius {

if(!(ary = try_as<Array>(obj))) {
if(CBOOL(obj->respond_to(state, G(sym_to_ary), cFalse))) {
if(!(obj = obj->send(state, call_frame, G(sym_to_ary)))) {
return false;
{
/* The references in args are not visible to the GC and
* there's not a simple mechanism to manage that now.
*/
ObjectMemory::GCInhibit inhibitor(state);

if(!(obj = obj->send(state, call_frame, G(sym_to_ary)))) {
return false;
}
}

if(!(ary = try_as<Array>(obj)) && !obj->nil_p()) {
Expand Down Expand Up @@ -264,15 +271,23 @@ namespace rubinius {
if(mcode->keywords && N > M) {
Object* obj = args.get_argument(args.total() - 1);

OnStack<1> os(state, obj);
Object* arguments[2];

arguments[0] = obj;
arguments[1] = RBOOL(O > 0 || RP);
Arguments args(G(sym_keyword_object), G(runtime), 2, arguments);
Dispatch dis(G(sym_keyword_object));
Dispatch dispatch(G(sym_keyword_object));

Object* kw_result;

Object* kw_result = dis.send(state, call_frame, args);
{
/* The references in args are not visible to the GC and
* there's not a simple mechanism to manage that now.
*/
ObjectMemory::GCInhibit inhibitor(state);

kw_result = dispatch.send(state, call_frame, args);
}

if(kw_result) {
if(Array* ary = try_as<Array>(kw_result)) {
Expand Down
113 changes: 63 additions & 50 deletions vm/builtin/call_site.cpp
Expand Up @@ -38,20 +38,29 @@ namespace rubinius {
return Integer::from(state, ip_);
}

Object* CallSite::empty_cache_custom(STATE, CallSite* call_site, CallFrame* call_frame,
Arguments& args)
Object* CallSite::empty_cache_custom(STATE, CallSite* call_site,
CallFrame* call_frame, Arguments& args)
{
Object* const recv = args.recv();

Array* ary = Array::create(state, args.total() + 2);
Array* ary = Array::create(state, args.total() + 2);
ary->set(state, 0, recv);
ary->set(state, 1, call_site->name_);

for(size_t i = 0; i < args.total(); i++) {
ary->set(state, i + 2, args.get_argument(i));
}

Object* ret = G(rubinius)->send(state, call_frame, state->symbol("bind_call"), ary);
Object* ret;

{
/* The references in args are not visible to the GC and
* there's not a simple mechanism to manage that now.
*/
ObjectMemory::GCInhibit inhibitor(state);

ret = G(rubinius)->send(state, call_frame, state->symbol("bind_call"), ary);
}

if(CallUnit* cu = try_as<CallUnit>(ret)) {
CallCustomCache* cache = CallCustomCache::create(state, call_site, cu);
Expand All @@ -63,28 +72,28 @@ namespace rubinius {
}
}

Object* CallSite::empty_cache(STATE, CallSite* call_site, CallFrame* call_frame,
Arguments& args)
Object* CallSite::empty_cache(STATE, CallSite* call_site,
CallFrame* call_frame, Arguments& args)
{
Object* const recv = args.recv();
Class* const recv_class = recv->direct_class(state);

LookupData lookup(call_frame->self(), recv->lookup_begin(state), G(sym_public));
Dispatch dis(call_site->name());
Dispatch dispatch(call_site->name());

if(!dis.resolve(state, call_site->name(), lookup)) {
if(!dispatch.resolve(state, call_site->name(), lookup)) {
if(!lookup_method_missing(state, call_frame, args,
dis, call_frame->self(), recv->lookup_begin(state))) {
dispatch, call_frame->self(), recv->lookup_begin(state))) {
return NULL;
}
}

state->vm()->metrics().machine.methods_invoked++;

call_site->update(state, recv_class, dis);
call_site->update(state, recv_class, dispatch);

Executable* meth = dis.method;
Module* mod = dis.module;
Executable* meth = dispatch.method;
Module* mod = dispatch.module;

if(meth->custom_call_site_p()) {
CallSiteInformation info(call_site->executable(), call_site->ip());
Expand All @@ -104,21 +113,21 @@ namespace rubinius {
Class* const recv_class = recv->direct_class(state);

LookupData lookup(call_frame->self(), recv->lookup_begin(state), G(sym_private));
Dispatch dis(call_site->name());
Dispatch dispatch(call_site->name());

if(!dis.resolve(state, dis.name, lookup)) {
if(!dispatch.resolve(state, dispatch.name, lookup)) {
if(!lookup_method_missing(state, call_frame, args,
dis, call_frame->self(), recv->lookup_begin(state))) {
dispatch, call_frame->self(), recv->lookup_begin(state))) {
return NULL;
}
}

state->vm()->metrics().machine.methods_invoked++;

call_site->update(state, recv_class, dis);
call_site->update(state, recv_class, dispatch);

Executable* meth = dis.method;
Module* mod = dis.module;
Executable* meth = dispatch.method;
Module* mod = dispatch.module;

if(meth->custom_call_site_p()) {
CallSiteInformation info(call_site->executable(), call_site->ip());
Expand All @@ -139,22 +148,22 @@ namespace rubinius {
Class* const recv_class = recv->direct_class(state);

LookupData lookup(call_frame->self(), recv->lookup_begin(state), G(sym_private));
Dispatch dis(call_site->name());
Dispatch dispatch(call_site->name());

if(!dis.resolve(state, call_site->name(), lookup)) {
dis.method_missing = eVCall;
if(!dispatch.resolve(state, call_site->name(), lookup)) {
dispatch.method_missing = eVCall;
if(!lookup_method_missing(state, call_frame, args,
dis, call_frame->self(), recv->lookup_begin(state))) {
dispatch, call_frame->self(), recv->lookup_begin(state))) {
return NULL;
}
}

state->vm()->metrics().machine.methods_invoked++;

call_site->update(state, recv_class, dis);
call_site->update(state, recv_class, dispatch);

Executable* meth = dis.method;
Module* mod = dis.module;
Executable* meth = dispatch.method;
Module* mod = dispatch.module;

if(meth->custom_call_site_p()) {
CallSiteInformation info(call_site->executable(), call_site->ip());
Expand All @@ -181,14 +190,15 @@ namespace rubinius {
Module* const start = call_frame->module()->superclass();

LookupData lookup(call_frame->self(), start, G(sym_private));
Dispatch dis(call_site->name());
Dispatch dispatch(call_site->name());

if(start->nil_p() || !dis.resolve(state, call_site->name(), lookup)) {
if(start->nil_p() || !dispatch.resolve(state, call_site->name(), lookup)) {

LookupData missing_lookup(call_frame->self(), recv->lookup_begin(state), G(sym_private));
Dispatch missing_dis(G(sym_method_missing));
LookupData missing_lookup(call_frame->self(),
recv->lookup_begin(state), G(sym_private));
Dispatch missing_dispatch(G(sym_method_missing));

if(!missing_dis.resolve(state, G(sym_method_missing), missing_lookup)) {
if(!missing_dispatch.resolve(state, G(sym_method_missing), missing_lookup)) {
std::ostringstream msg;
msg << "no method_missing for ";
msg << recv_class->to_string(state);
Expand All @@ -199,19 +209,19 @@ namespace rubinius {
}

args.unshift(state, call_site->name());
dis.method = missing_dis.method;
dis.module = missing_dis.module;
dis.method_missing = eSuper;
state->vm()->set_method_missing_reason(dis.method_missing);
dispatch.method = missing_dispatch.method;
dispatch.module = missing_dispatch.module;
dispatch.method_missing = eSuper;
state->vm()->set_method_missing_reason(dispatch.method_missing);
state->vm()->global_cache()->add_seen(state, call_site->name());
}

state->vm()->metrics().machine.methods_invoked++;

call_site->update(state, recv_class, dis);
call_site->update(state, recv_class, dispatch);

Executable* meth = dis.method;
Module* mod = dis.module;
Executable* meth = dispatch.method;
Module* mod = dispatch.module;

if(meth->custom_call_site_p()) {
CallSiteInformation info(call_site->executable(), call_site->ip());
Expand Down Expand Up @@ -245,34 +255,37 @@ namespace rubinius {
}

LookupData lookup(call_frame->self(), recv->lookup_begin(state), G(sym_public));
Dispatch dis(name_);
Dispatch dispatch(name_);

if(dis.resolve(state, name_, lookup)) {
update(state, recv_class, dis);
return dis.method->serial()->to_native() == serial;
if(dispatch.resolve(state, name_, lookup)) {
update(state, recv_class, dispatch);
return dispatch.method->serial()->to_native() == serial;
}
return false;
}

bool CallSite::lookup_method_missing(STATE, CallFrame* call_frame, Arguments& args, Dispatch& dis, Object* self, Module* begin) {
bool CallSite::lookup_method_missing(STATE, CallFrame* call_frame,
Arguments& args, Dispatch& dispatch, Object* self, Module* begin)
{
LookupData missing_lookup(self, begin, G(sym_private));
Dispatch missing_dis(G(sym_method_missing));
Dispatch missing_dispatch(G(sym_method_missing));

if(!missing_dis.resolve(state, G(sym_method_missing), missing_lookup)) {
if(!missing_dispatch.resolve(state, G(sym_method_missing), missing_lookup)) {
std::ostringstream msg;
msg << "no method_missing for ";
msg << begin->to_string(state);
msg << "#" << dis.name->to_string(state);
msg << "#" << dispatch.name->to_string(state);

Exception::internal_error(state, call_frame, msg.str().c_str());
return false;
}

args.unshift(state, dis.name);
dis.method = missing_dis.method;
dis.module = missing_dis.module;
state->vm()->set_method_missing_reason(dis.method_missing);
state->vm()->global_cache()->add_seen(state, dis.name);
args.unshift(state, dispatch.name);
dispatch.method = missing_dispatch.method;
dispatch.module = missing_dispatch.module;
state->vm()->set_method_missing_reason(dispatch.method_missing);
state->vm()->global_cache()->add_seen(state, dispatch.name);

return true;
}

Expand Down
10 changes: 6 additions & 4 deletions vm/builtin/executable.cpp
Expand Up @@ -49,13 +49,15 @@ namespace rubinius {
return execute(state, call_frame, this, mod, args);
}

Object* Executable::default_executor(STATE, CallFrame* call_frame, Executable* exec, Module* mod,
Arguments& args) {
Object* Executable::default_executor(STATE, CallFrame* call_frame,
Executable* exec, Module* mod, Arguments& args)
{
args.unshift2(state, args.recv(), args.name());
args.set_recv(exec);

Dispatch dis(G(sym_call));
return dis.send(state, call_frame, args);
Dispatch dispatch(G(sym_call));

return dispatch.send(state, call_frame, args);
}

void Executable::add_inliner(STATE, ObjectMemory* om, CompiledCode* code) {
Expand Down

0 comments on commit 65b9bd1

Please sign in to comment.