forked from rubinius/rubinius
/
variable_scope.cpp
128 lines (100 loc) · 3.61 KB
/
variable_scope.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
122
123
124
125
126
127
128
#include "vm.hpp"
#include "objectmemory.hpp"
#include "call_frame.hpp"
#include "gc/gc.hpp"
#include "builtin/object.hpp"
#include "builtin/variable_scope.hpp"
#include "builtin/class.hpp"
#include "builtin/system.hpp"
#include "builtin/tuple.hpp"
#include "builtin/fiber.hpp"
#include "fiber_data.hpp"
#include "ontology.hpp"
namespace rubinius {
void VariableScope::init(STATE) {
GO(variable_scope).set(ontology::new_class(state,
"VariableScope", G(object), G(rubinius)));
G(variable_scope)->set_object_type(state, VariableScopeType);
}
void VariableScope::bootstrap_methods(STATE) {
GCTokenImpl gct;
System::attach_primitive(state, gct,
G(variable_scope), false,
state->symbol("method_visibility"),
state->symbol("variable_scope_method_visibility"));
}
VariableScope* VariableScope::of_sender(STATE, CallFrame* call_frame) {
CallFrame* dest = call_frame->previous;
// Skip any frames for native methods
while(dest->native_method_p()) { dest = dest->previous; }
return dest->promote_scope(state);
}
VariableScope* VariableScope::current(STATE, CallFrame* call_frame) {
if(call_frame->native_method_p()) return nil<VariableScope>();
return call_frame->promote_scope(state);
}
VariableScope* VariableScope::synthesize(STATE, CompiledCode* method,
Module* module, Object* parent,
Object* self, Object* block,
Tuple* locals)
{
VariableScope* scope = state->new_object<VariableScope>(G(variable_scope));
scope->block(state, block);
scope->module(state, module);
scope->method(state, method);
if(VariableScope* vs = try_as<VariableScope>(parent)) {
scope->parent(state, vs);
} else {
scope->parent(state, nil<VariableScope>());
}
scope->heap_locals(state, locals);
scope->last_match(state, cNil);
scope->self(state, self);
scope->number_of_locals_ = locals->num_fields();
scope->isolated_ = true;
scope->locals_ = 0;
scope->block_as_method_ = 0;
return scope;
}
Tuple* VariableScope::locals(STATE) {
Tuple* tup = Tuple::create(state, number_of_locals_);
for(int i = 0; i < number_of_locals_; i++) {
tup->put(state, i, get_local(state, i));
}
return tup;
}
Object* VariableScope::set_local_prim(STATE, Fixnum* number, Object* object) {
int num = number->to_int();
if(num < 0) {
Exception::argument_error(state, "negative local index");
} else if (num >= number_of_locals_) {
Exception::argument_error(state, "index larger than number of locals");
}
set_local(state, num, object);
return cNil;
}
// bootstrap method, replaced with an attr_accessor in kernel.
Object* VariableScope::method_visibility(STATE) {
return cNil;
}
void VariableScope::Info::mark(Object* obj, ObjectMark& mark) {
auto_mark(obj, mark);
VariableScope* vs = as<VariableScope>(obj);
vs->fixup();
if(!vs->isolated()) {
Object** ary = vs->stack_locals();
if(Fiber* fib = try_as<Fiber>(vs->fiber())) {
FiberData* data = fib->data();
AddressDisplacement dis(data->data_offset(),
data->data_lower_bound(),
data->data_upper_bound());
ary = dis.displace(ary);
}
size_t locals = vs->number_of_locals();
for(size_t i = 0; i < locals; i++) {
Object* tmp = mark.call(ary[i]);
if(tmp) { ary[i] = tmp; }
}
}
}
}