/
access_variable.cpp
121 lines (103 loc) · 4.02 KB
/
access_variable.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "arguments.hpp"
#include "builtin/access_variable.hpp"
#include "builtin/class.hpp"
#include "builtin/executable.hpp"
#include "builtin/exception.hpp"
#include "builtin/packed_object.hpp"
#include "builtin/symbol.hpp"
#include "object_utils.hpp"
#include "objectmemory.hpp"
#include "ontology.hpp"
namespace rubinius {
void AccessVariable::init(STATE) {
// HACK test superclass of AccessVariable
GO(access_variable).set(ontology::new_class(state,
"AccessVariable", G(executable), G(rubinius)));
G(access_variable)->set_object_type(state, AccessVariableType);
}
AccessVariable* AccessVariable::allocate(STATE) {
AccessVariable* av = state->new_object<AccessVariable>(G(access_variable));
av->inliners_ = 0;
av->prim_index_ = -1;
av->custom_call_site_ = false;
av->set_executor(AccessVariable::access_execute);
return av;
}
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());
}
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, recv);
return 0;
}
return recv->set_ivar(state, access->name(), args.get_argument(0));
}
/* 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, self);
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());
}
} // rubinius