/* Run when an AccessVariable is executed. Uses the details in exec * to access instance variables of args.recv() */ Object* AccessVariable::access_execute(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args) { AccessVariable* access = as<AccessVariable>(exec); Object* const self = args.recv(); /* The writer case. */ if(access->write()->true_p()) { if(CBOOL(self->frozen_p(state))) { Exception::frozen_error(state, call_frame); return 0; } if(args.total() != 1) { Exception::argument_error(state, 1, args.total()); return NULL; } if(kind_of<Class>(mod) && self->reference_p()) { // Promote this to use a direct accessor if(TypeInfo* ti = state->memory()->find_type_info(self)) { TypeInfo::Slots::iterator it = ti->slots.find(access->name()->index()); if(it != ti->slots.end()) { // Found one! access->set_executor(ti->slot_accessors[it->second]); ti->set_field(state, self, it->second, args.get_argument(0)); return args.get_argument(0); } } /* Fall through, handle it as a normal ivar. */ access->set_executor(access_write_regular_ivar); } self->set_ivar(state, access->name(), args.get_argument(0)); return args.get_argument(0); } /* The read case. */ if(args.total() != 0) { Exception::argument_error(state, 0, args.total()); return NULL; } if(kind_of<Class>(mod) && self->reference_p()) { // Promote this to use a direct accessor if(TypeInfo* ti = state->memory()->find_type_info(self)) { TypeInfo::Slots::iterator it = ti->slots.find(access->name()->index()); if(it != ti->slots.end()) { // Found one! access->set_executor(ti->slot_accessors[it->second]); return ti->get_field(state, self, it->second); } } // Ok, its a table ivar, setup fast access for next time. access->set_executor(access_read_regular_ivar); } return self->get_ivar(state, access->name()); }
void test_access_variable() { AccessVariable* av = AccessVariable::allocate(state); Arguments args(state->symbol("blah"), G(object)); av->name(state, state->symbol("@blah")); G(object)->set_ivar(state, av->name(), state->symbol("Sweet")); Object* ret = av->execute(state, av, G(object), args); TS_ASSERT(try_as<Symbol>(ret)); TS_ASSERT_EQUALS(std::string("Sweet"), as<Symbol>(ret)->cpp_str(state)); }
void test_write_variable() { AccessVariable* av = AccessVariable::allocate(state); Symbol* val = state->symbol("Blah"); Object* ary[1] = {val}; Arguments args(state->symbol("blah"), G(object), 1, ary); av->name(state, state->symbol("@blah")); av->write(state, cTrue); Object* ret = av->execute(state, av, G(object), args); TS_ASSERT_EQUALS(ret, val); Symbol* out = as<Symbol>(G(object)->get_ivar(state, av->name())); TS_ASSERT_EQUALS(val, out); }
Object* AccessVariable::access_read_regular_ivar(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args) { AccessVariable* access = as<AccessVariable>(exec); if(unlikely(args.total() != 0)) { Exception::argument_error(state, 0, args.total()); return NULL; } Object* recv = args.recv(); // Handle packed objects in a unique way. if(PackedObject* po = try_as<PackedObject>(recv)) { return po->get_packed_ivar(state, access->name()); } return recv->get_table_ivar(state, access->name()); }
void test_access_variable() { AccessVariable* av = AccessVariable::allocate(state); Task* task = Task::create(state, 10); Message msg(state); msg.recv = G(object); msg.method = av; msg.use_from_task(task, 0); av->name(state, state->symbol("@blah")); G(object)->set_ivar(state, av->name(), state->symbol("Sweet")); TS_ASSERT(!av->execute(state, task, msg)); Object* ret = task->pop(); TS_ASSERT(try_as<Symbol>(ret)); TS_ASSERT_EQUALS(std::string("Sweet"), as<Symbol>(ret)->c_str(state)); }
Object* AccessVariable::access_read_regular_ivar(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args) { AccessVariable* access = as<AccessVariable>(exec); if(unlikely(args.total() != 0)) { Exception::argument_error(state, 0, args.total()); return NULL; } Object* recv = args.recv(); return recv->get_ivar(state, access->name()); }
void test_access_variable_is_slot() { AccessVariable* av = AccessVariable::allocate(state); Arguments args(state->symbol("blah"), G(object)); av->name(state, state->symbol("@module_name")); Object* ret = av->access_execute(state, av, G(object), args); TS_ASSERT(try_as<Symbol>(ret)); TS_ASSERT_EQUALS(std::string("Object"), as<Symbol>(ret)->cpp_str(state)); }
void test_write_variable() { AccessVariable* av = AccessVariable::allocate(state); Task* task = Task::create(state, 10); Message msg(state); msg.recv = G(object); msg.method = av; msg.use_from_task(task, 0); av->name(state, state->symbol("@blah")); av->write(state, Qtrue); Symbol* val = state->symbol("Blah"); msg.unshift_argument(state, val); TS_ASSERT(!av->execute(state, task, msg)); Object* ret = task->pop(); TS_ASSERT_EQUALS(ret, val); Symbol* out = as<Symbol>(G(object)->get_ivar(state, av->name())); TS_ASSERT_EQUALS(val, out); }
Object* AccessVariable::access_write_regular_ivar(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args) { AccessVariable* access = as<AccessVariable>(exec); if(unlikely(args.total() != 1)) { Exception::argument_error(state, 1, args.total()); return NULL; } Object* recv = args.recv(); if(CBOOL(recv->frozen_p(state))) { Exception::frozen_error(state, call_frame); return 0; } // Handle packed objects in a unique way. if(PackedObject* po = try_as<PackedObject>(recv)) { return po->set_packed_ivar(state, access->name(), args.get_argument(0)); } return recv->set_table_ivar(state, access->name(), args.get_argument(0)); }
void test_access_variable_is_slot() { AccessVariable* av = AccessVariable::allocate(state); CallFrame cf; Dispatch dis(state->symbol("blah"), G(object), av); Arguments args(G(object), 0, 0); av->name(state, state->symbol("@name")); Object* ret = av->access_execute(state, &cf, dis, args); TS_ASSERT(try_as<Symbol>(ret)); TS_ASSERT_EQUALS(std::string("Object"), as<Symbol>(ret)->c_str(state)); }
void test_write_variable_is_slot() { AccessVariable* av = AccessVariable::allocate(state); Symbol* val = state->symbol("Blah"); Object* ary[1] = {val}; Arguments args(state->symbol("blah"), G(object), 1, ary); av->name(state, state->symbol("@module_name")); av->write(state, cTrue); Object* ret = av->access_execute(state, av, G(object), args); TS_ASSERT_EQUALS(ret, val); TS_ASSERT_EQUALS(val, G(object)->module_name()); }
/* Run when an AccessVariable is executed. Uses the details in msg.method * to access instance variables of msg.recv */ ExecuteStatus AccessVariable::access_execute(STATE, Task* task, Message& msg) { AccessVariable* access = as<AccessVariable>(msg.method); /* The writer case. */ if(access->write()->true_p()) { if(msg.args() != 1) { Exception::argument_error(state, 1, msg.args()); } /* Fall through, handle it as a normal ivar. */ msg.recv->set_ivar(state, access->name(), msg.get_argument(0)); task->primitive_return(msg.get_argument(0), msg); return cExecuteContinue; } /* The read case. */ if(msg.args() != 0) { Exception::argument_error(state, 0, msg.args()); } else { task->primitive_return(msg.recv->get_ivar(state, access->name()), msg); } return cExecuteContinue; }
void test_write_variable_is_slot() { AccessVariable* av = AccessVariable::allocate(state); CallFrame cf; Dispatch dis(state->symbol("blah"), G(object), av); Symbol* val = state->symbol("Blah"); Object* ary[1] = {val}; Arguments args(G(object), 1, ary); av->name(state, state->symbol("@name")); av->write(state, Qtrue); Object* ret = av->access_execute(state, &cf, dis, args); TS_ASSERT_EQUALS(ret, val); TS_ASSERT_EQUALS(val, G(object)->name()); }
Object* AccessVariable::access_write_regular_ivar(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args) { AccessVariable* access = as<AccessVariable>(exec); if(unlikely(args.total() != 1)) { Exception::argument_error(state, 1, args.total()); return NULL; } Object* recv = args.recv(); if(CBOOL(recv->frozen_p(state)) && CBOOL(recv->frozen_mod_disallowed(state))) { Exception::frozen_error(state, call_frame, recv); return 0; } return recv->set_ivar(state, access->name(), args.get_argument(0)); }